//	Copyright (c) 2005, 2006, 2007, 2008, 2009, 2010 Christian Staudenmeyer
//
//	Permission is hereby granted, free of charge, to any person obtaining
//	a copy of this software and associated documentation files (the
//	"Software"), to deal in the Software without restriction, including
//	without limitation the rights to use, copy, modify, merge, publish,
//	distribute, sublicense, and/or sell copies of the Software, and to
//	permit persons to whom the Software is furnished to do so, subject to
//	the following conditions:
//
//	The above copyright notice and this permission notice shall
//	included in all copies or substantial portions of the Software.
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
//	BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
//	ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//	CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//	SOFTWARE.


using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Globalization;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Meta.Fusion;
using System.Security;
using Oyster.Math;

namespace Meta
{
	public delegate void DebugDelegate(Map context);
	public class Interpreter
	{
		public static List<Statement> stopStatements = new List<Statement>();
		public static bool simulate;
		public static bool stopping = false;
		public static DebugDelegate Breakpoint;
		public static List<Source> breakpoints = new List<Source>();
		public static Map Run(string path, Map argument)
		{
			return Run(path, argument, true);
		}
		public static Map Run(string path, Map argument, bool optimize)
		{
			// refactor
			Directory.SetCurrentDirectory(Path.GetDirectoryName(path));

			Map callable = Parser.Parse(path);
			callable.GetExpression();
			callable.Scope = Versions.versions;

			foreach (Source breakpoint in breakpoints)
			{
				Source key = breakpoint;
				while (!Meta.Expression.sources.ContainsKey(key))
				{
					key = new Source(key.Line, key.Column + 1, key.Index, key.FileName);
				}
				if (Meta.Expression.sources.ContainsKey(key))
				{
					Meta.Expression.sources[key][0].BreakPoint = key;
				}
			}
			if (optimize)
			{
				callable.Expression = callable.GetExpression().Optimize().Optimize();
			}
			return callable.Call(argument);
		}
		public static bool profiling = false;
		public static string LibPath
		{
			get
			{
				return Path.Combine(InstallationPath, "Cache");
			}
		}
		[DllImport("kernel32")]
		public extern static int LoadLibrary(string lpLibFileName);
		public delegate string TestDelegate();
		//[STAThread]
		//public static void Main(string[] args)
		//{
		//    if (args.Length != 0)
		//    {
		//        if (args[0] == "-test")
		//        {
		//            UseConsole();
		//            new Test.MetaTest().Run();
		//        }
		//        else if (args[0] == "-nprof")
		//        {
		//            Interpreter.Run(Path.Combine(Interpreter.InstallationPath, @"libraryTest.meta"), new DictionaryMap());
		//        }
		//        else if (args[0] == "-profile")
		//        {
		//            UseConsole();
		//            Interpreter.profiling = true;
		//            Interpreter.Run(Path.Combine(Interpreter.InstallationPath, @"game.meta"), new DictionaryMap());
		//            List<object> results = new List<object>(Map.calls.Keys);
		//            results.Sort(delegate(object a, object b)
		//            {
		//                return Map.calls[b].time.CompareTo(Map.calls[a].time);
		//            });
		//            foreach (object e in results)
		//            {
		//                Console.WriteLine(e.ToString() + "    " + Map.calls[e].time + "     " + Map.calls[e].calls);
		//            }
		//        }
		//        else if (args[0] == "-performance")
		//        {
		//            UseConsole();
		//            Interpreter.Run(Path.Combine(Interpreter.InstallationPath, @"learning.meta"), new DictionaryMap());
		//        }
		//        else if (args[0].Trim().StartsWith("meta:"))
		//        {
		//            Map directory = new DirectoryMap(Directory.GetCurrentDirectory());
		//            directory.Scope = Versions.versions;

		//            Map callable = Parser.ParseExpression(args[0].Trim().Substring("meta:".Length), "console");
		//            callable.Scope = directory;
		//            Map result = callable.Call(EmptyMap.Empty);

		//        }
		//        else
		//        {
		//            Map directory = new DirectoryMap(Directory.GetCurrentDirectory());
		//            directory.Scope = Versions.versions;
		//            string fileName = args[0].Trim('"');
		//            if (File.Exists(fileName))
		//            {
		//                try
		//                {
		//                    Interpreter.Run(fileName, new DictionaryMap());
		//                }
		//                catch (Exception e)
		//                {
		//                    Console.WriteLine(e.Message+"\n"+e.StackTrace);
		//                    Console.ReadLine();
		//                }
		//            }
		//            else
		//            {
		//                Console.WriteLine("File " + fileName + " not found.");
		//                Console.ReadLine();
		//            }
		//        }
		//    }
		//}
		[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
		public static extern bool AllocConsole();
		public static bool useConsole = false;
		public static void UseConsole()
		{
			if (!useConsole)
			{
				AllocConsole();
			}
			useConsole = true;
		}
		// TODO: use installation path here
		public static string TestPath
		{
			get
			{
				DirectoryInfo directory = new DirectoryInfo(InstallationPath);
				while (true)
				{
					DirectoryInfo test = new DirectoryInfo(Path.Combine(directory.FullName, "Test"));
					if (test.Exists)
					{
						return test.FullName;
					}
					else
					{
						directory = directory.Parent;
					}
				}
			}
		}
		public static string LibraryPath
		{
			get
			{
				DirectoryInfo directory = new DirectoryInfo(InstallationPath);
				while (true)
				{
					//DirectoryInfo test = new DirectoryInfo(Path.Combine(directory.FullName, "Library"));
					FileInfo test = new FileInfo(Path.Combine(directory.FullName, "library.meta"));
					//DirectoryInfo test = new DirectoryInfo(Path.Combine(directory.FullName, "Library"));
					if (test.Exists)
					{
						return test.FullName;
					}
					else
					{
						directory = directory.Parent;
					}
				}
			}
		}
		public static string _installationPath;
		public static string InstallationPath
		{
			get
			{
				if (_installationPath == null)
				{
					string directory=System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
					while (!File.Exists(Path.Combine(directory,"library.meta")))
					{
						directory = Directory.GetParent(directory).FullName;
					}
					_installationPath = directory;
				}
				return _installationPath;
				// TODO: fix this
				//return "C:\\Projects\\Meta\\bin\\Debug";
				//return System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///",""));// Process.GetCurrentProcess().MainModule.FileName);
				//return System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
			}
		}
	}

	public class Profile
	{
		public double time;
		public int calls;
		public int recursive;
	}
	public interface ISerializeEnumerableSpecial
	{
		string Serialize(bool key);
	}
	public class ExceptionLog
	{
		public ExceptionLog(Source source)
		{
			this.source = source;
		}
		public Source source;
	}
	public class MetaException : Exception
	{
		private string message;
		private Source source;
		private List<ExceptionLog> invocationList = new List<ExceptionLog>();
		public MetaException(string message, Source source)
		{
			if (message.Length < 1000)
			{
				this.message = message;
			}
			else
			{
				this.message = message.Substring(0, 1000) + "...";
			}
			this.source = source;
		}
		public List<ExceptionLog> InvocationList
		{
			get
			{
				return invocationList;
			}
		}
		public override string ToString()
		{
			string message = Message;
			if (invocationList.Count != 0)
			{
				message += "\n\nStack trace:";
			}
			foreach (ExceptionLog log in invocationList)
			{
				message += "\n" + GetSourceText(log.source);
			}
			return message;
		}
		public static string GetSourceText(Source source)
		{
			string text;
			if (source != null)
			{
				text = source.FileName + ", line ";
				text += source.Line + ", column " + source.Column;
			}
			else
			{
				text = "Unknown location";
			}
			return text;
		}
		public override string Message
		{
			get
			{
				return GetSourceText(source) + ": " + message;
			}
		}
		public Source Source
		{
			get
			{
				return source;
			}
		}
		public static int CountLeaves(Map map)
		{
			int count = 0;
			foreach (KeyValuePair<Map, Map> pair in map)
			{
				if (pair.Value == null)
				{
					count++;
				}
				else if (pair.Value.GetNumber() != null)
				{
					count++;
				}
				else
				{
					count += CountLeaves(pair.Value);
				}
			}
			return count;
		}
	}
	[Serializable]
	public abstract class DotNetMap : ScopeMap
	{
		public override IEnumerable<Map> Array
		{
			get
			{

				yield break;
			}
		}
		public override void Append(Map map)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override string GetString()
		{
			return null;
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override int GetHashCode()
		{
			if (obj != null)
			{
				return obj.GetHashCode();
			}
			return type.GetHashCode();
		}
		public override bool Equals(object obj)
		{
			DotNetMap dotNet = obj as DotNetMap;
			return dotNet != null && dotNet.Object == Object && dotNet.Type == Type;
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public object Object
		{
			get
			{
				return obj;
			}
		}
		public Type Type
		{
			get
			{
				return type;
			}
		}
		protected abstract object GlobalKey
		{
			get;
		}
		public static string GetMethodName(MethodInfo method)
		{
			string name = method.Name;
			name = name.Substring(Math.Max(0, name.LastIndexOf('.') + 1));
			foreach (ParameterInfo parameter in method.GetParameters())
			{
				name += "_" + parameter.ParameterType.Name.Replace("&", "");
			}
			return name;
		}
		private Dictionary<Map, Member> data;
		public Dictionary<Map, Member> Members
		{
			get
			{
				if (data == null)
				{
					data = MemberCache.GetMembers(type);
				}
				return data;
			}
		}
		protected abstract MemberCache MemberCache
		{
			get;
		}
		private object obj;
		private Type type;
		public DotNetMap(object obj, Type type)
		{
			this.obj = obj;
			this.type = type;
			//if (obj is TestClass.Subclass)
			//{
			//}
		}
		public override Map this[Map key]
		{
			get
			{
				if (Members.ContainsKey(key))
				{
					return Members[key].Get(obj);
				}
				if (GlobalKey != null && global.ContainsKey(GlobalKey) && global[GlobalKey].ContainsKey(key))
				{
					return global[GlobalKey][key];
				}
				return null;
			}
			set
			{
				if (Members.ContainsKey(key))
				{
					Members[key].Set(obj, value);
				}
				else
				{
					if (!global.ContainsKey(GlobalKey))
					{
						global[GlobalKey] = new Dictionary<Map, Map>();
					}
					global[GlobalKey][key] = value;
				}
			}
		}
		public static Dictionary<object, Dictionary<Map, Map>> global = new Dictionary<object, Dictionary<Map, Map>>();
		public override bool ContainsKey(Map key)
		{
			return this[key] != null;
		}
		public override int Count
		{
			get
			{
				return new List<Map>(Keys).Count;
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				foreach (Map key in Members.Keys)
				{
					yield return key;
				}
				if (GlobalKey != null)
				{
					if (global.ContainsKey(GlobalKey))
					{
						foreach (Map key in global[GlobalKey].Keys)
						{
							yield return key;
						}
					}
				}
			}
		}
		public override string Serialize(bool key)
		{
			if (obj != null)
			{
				return this.obj.ToString();
			}
			else
			{
				return this.type.ToString();
			}
		}
	}
	public class MemberCache
	{
		private BindingFlags bindingFlags;
		public MemberCache(BindingFlags bindingFlags)
		{
			this.bindingFlags = bindingFlags;
		}
		public Dictionary<Map, Member> GetMembers(Type type)
		{
			if (!cache.ContainsKey(type))
			{
				Dictionary<Map, Member> data = new Dictionary<Map, Member>();
				foreach (MemberInfo member in type.GetMembers(bindingFlags))
				{
					MethodInfo method = member as MethodInfo;
					if (method != null)
					{
						if (!method.IsSpecialName || method.Name.StartsWith("op_"))
						{
							string name = TypeMap.GetMethodName(method);
							if (!data.ContainsKey(name))
							{
								data[name] = new MethodMember(method, method, type);
							}
						}

					}
					FieldInfo field = member as FieldInfo;
					if (field != null && field.IsPublic)
					{
						data[field.Name] = new FieldMember(field);
					}
					PropertyInfo property = member as PropertyInfo;
					if (property != null)
					{
						data[property.Name] = new PropertyMember(property, type);
					}
					EventInfo eventInfo = member as EventInfo;
					if (eventInfo != null)
					{
						data[eventInfo.Name] = new EventMember(eventInfo, type);
					}
					Type t = member as Type;
					if (t != null)
					{
						data[t.Name] = new TypeMember(t);
					}
				}
				cache[type] = data;
			}
			return cache[type];
		}
		private Dictionary<Type, Dictionary<Map, Member>> cache = new Dictionary<Type, Dictionary<Map, Member>>();
	}
	[Serializable]
	public class TypeMap : DotNetMap
	{
		public override Type GetClass()
		{
			return this.Type;
		}
		public static MemberCache cache = new MemberCache(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);

		protected override MemberCache MemberCache
		{
			get
			{
				return cache;
			}
		}
		public override string ToString()
		{
			return Type.ToString();
		}
		protected override object GlobalKey
		{
			get
			{
				return this;
			}
		}
		public TypeMap(Type type)
			: base(null, type)
		{
		}
		public override bool ContainsKey(Map key)
		{
			return this[key] != null;
		}
		public override Map this[Map key]
		{
			get
			{
				return base[key];
				if (Type.IsGenericTypeDefinition && key is TypeMap)
				{
					List<Type> types = new List<Type>();
					if (Type.GetGenericArguments().Length == 1)
					{
						types.Add(((TypeMap)key).Type);
					}
					else
					{
						foreach (Map map in key.Array)
						{
							types.Add(((TypeMap)map).Type);
						}
					}
					return new TypeMap(Type.MakeGenericType(types.ToArray()));
				}
				else if (Type == typeof(Array) && key is TypeMap)
				{
					return new TypeMap(((TypeMap)key).Type.MakeArrayType());
				}
				else if (base[key] != null)
				{
					return base[key];
				}
				else
				{
					return null;
				}
			}
		}
		public static string GetConstructorName(ConstructorInfo constructor)
		{
			string name = constructor.DeclaringType.Name;
			foreach (ParameterInfo parameter in constructor.GetParameters())
			{
				if (parameter.ParameterType.IsArray)
				{
					name += "_" + parameter.ParameterType.Name.Trim('[', ']') + "Array";
				}
				else
				{
					name += "_" + parameter.ParameterType.Name;
				}
			}
			return name;
		}
		public override Map Copy()
		{
			return new TypeMap(this.Type);
		}
		private Method constructor;
		public Method Constructor
		{
			get
			{
				if (constructor == null)
				{
					ConstructorInfo method = Type.GetConstructor(new Type[] { });
					if (method != null)
					{
						constructor = new Method(method, Object, Type, method);
					}
				}
				return constructor;
			}
		}
		public override Map Call(Map argument)
		{
			// special case for debugging in WPF-Editor
			//if (this.Type.Equals(typeof(System.Windows.Application)) && Interpreter.WindowsApplication != null)
			//{
			//    return Library.With(new ObjectMap(Interpreter.WindowsApplication), argument);
			//}
			if (Interpreter.simulate)
			{
				//if (!argument.Array.Where(a => !(a is ObjectMap)).Any())
				//{
				//    var args = argument.Array.Select(a => ((ObjectMap)a).Object).ToArray();
				//    ConstructorInfo method = this.Type.GetConstructor(argument.Array.Select(a => ((ObjectMap)a).Type).ToArray());//args.Select(a=>a.GetType()).ToArray());//.GetMethod(name);
				//    if (method != null)
				//    {
				//if (this.Type.IsPrimitive)
				//{
				//    return new DictionaryMap();
				//}
				//else
				//{
				return new ObjectMap(null, this.Type);
				//}
				//    }
				//}
				//return new DictionaryMap();
			}
			else
			{
				object[] args;
				if (argument == null)
				{
					args = new object[0];
				}
				else
				{
					args = new List<Map>(argument.Array).ConvertAll(new Converter<Map, object>(delegate(Map m) { return ((ObjectMap)m).Object; })).ToArray();
				}

				return Transform.ToMeta(this.Type.InvokeMember(".ctor", BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, args));
			}
		}
	}
	[Serializable]
	public class ObjectMap : DotNetMap
	{
		public override object GetObject()
		{
			return Object;
		}
		public static MemberCache cache = new MemberCache(BindingFlags.Public | BindingFlags.Instance);

		public static MemberCache allCache = new MemberCache(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
		protected override MemberCache MemberCache
		{
			get
			{
				return cache;
			}
		}
		protected override object GlobalKey
		{
			get
			{
				return Object;
			}
		}
		public override Map Call(Map arg)
		{
			if (this.Type.IsSubclassOf(typeof(Delegate)))
			{
				MethodInfo invoke = Type.GetMethod("Invoke");
				return new Method(invoke, this.Object, Type, invoke).Call(arg);
			}
			else
			{
				throw new Exception("The object is not callable.");
			}
		}
		public override int GetHashCode()
		{
			if (Object == null)
			{
				return 0;
			}
			return Object.GetHashCode();
		}
		public override bool Equals(object o)
		{
			return o is ObjectMap && Object.Equals(((ObjectMap)o).Object);
		}
		public ObjectMap(string text) : this(text, text.GetType()) { }
		public ObjectMap(object target, Type type)
			: base(target, type)
		{
		}
		public ObjectMap(object target)
			: base(target, target.GetType())
		{
		}
		public override string ToString()
		{
			if (Object == null)
			{
				return null;
			}
			else
			{
				return Object.ToString();
			}
		}
		public override Map Copy()
		{
			return this;
		}
	}

	public abstract class Member
	{
		public abstract MemberInfo Original
		{
			get;
		}
		public abstract void Set(object obj, Map value);
		public abstract Map Get(object obj);
	}
	public class TypeMember : Member
	{
		public override MemberInfo Original
		{
			get
			{
				return type;
			}
		}
		public override void Set(object obj, Map value)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		private Type type;
		public TypeMember(Type type)
		{
			this.type = type;
		}
		public override Map Get(object obj)
		{
			return new TypeMap(type);
		}
	}
	public class FieldMember : Member
	{
		public override MemberInfo Original
		{
			get
			{
				return field;
			}
		}
		private FieldInfo field;
		public FieldMember(FieldInfo field)
		{
			this.field = field;
		}
		public override void Set(object obj, Map value)
		{
			field.SetValue(obj, Transform.ToDotNet(value, field.FieldType));
		}
		public override Map Get(object obj)
		{
			return Transform.ToMeta(field.GetValue(obj));
		}
	}
	public class MethodMember : Member
	{
		public override MemberInfo Original
		{
			get
			{
				return original;
			}
		}
		private MemberInfo original;
		public MethodBase method;
		public Type type;
		public MethodMember(MethodInfo method, MemberInfo original, Type type)
		{
			this.type = type;
			this.method = method;
			this.original = original;
		}
		public override void Set(object obj, Map value)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override Map Get(object obj)
		{
			return new Method(method, obj, type, original);
		}
	}
	[Serializable]
	public abstract class MethodBaseMap : Map
	{
		public override Map this[Map key]
		{
			get
			{
				return null;
			}
			set
			{
				throw new MetaException("Cannot set key in method map.", null);
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				yield break;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override int Count
		{
			get
			{
				return 0;
			}
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override Map Copy()
		{
			return this;
		}
		public override bool ContainsKey(Map key)
		{
			return false;
		}
	}
	[Serializable]
	public class Method : ScopeMap
	{
		public override void Append(Map map)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override int Count
		{
			get
			{
				return 0;
			}
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override string GetString()
		{
			return null;
		}
		public override string Serialize(bool key)
		{
			return method.ToString();
		}
		public override int GetHashCode()
		{
			return method.GetHashCode();
		}
		public override bool Equals(object obj)
		{
			Method method = obj as Method;
			if (method != null)
			{
				return this.method.Equals(method.method);
			}
			return false;
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override bool ContainsKey(Map key)
		{
			return false;
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				yield break;
			}
		}
		public override Map this[Map key]
		{
			get
			{
				return null;
			}
			set
			{
				// TODO: implement this?
				throw new Exception("The method or operation is not implemented.");
			}
		}
		public override Map Copy()
		{
			return this;
		}
		[Ignore]
		public MethodBase method;
		protected object obj;
		[Ignore]
		public MemberInfo original;
		public delegate Map Caller(Map[] arguments);
		private Caller _caller;
		private Caller CallerMethod
		{
			get
			{
				if (_caller == null)
				{
					this.returnType = ((MethodInfo)method).ReturnType;
					MethodInfo m = (MethodInfo)method;
					ParameterInfo[] pars = method.GetParameters();

					il = new Emitter(typeof(Caller), obj.GetType());
					if (type.IsValueType)
					{
						LocalBuilder local = il.DeclareLocal(type);
						il.LoadArgument(0);
						il.UnboxAny(type);
						il.StoreLocal(local);
						il.LoadLocalAddress(local);
					}
					else
					{
						il.LoadArgument(0);
					}

					for (int i = 0; i < pars.Length; i++)
					{
						il.LoadArgument(1);
						il.LoadElement(i);
						il.CastClass(typeof(Map));
						Transform.GetDotNetConversion(pars[i].ParameterType, il);
					}
					if (obj.GetType() != type || type.IsValueType)
					{
						if (type.IsValueType && method.IsVirtual)
						{
							il.Constrained(type);
							il.Call(m);

						}
						else
						{
							il.CallNonVirtual(m);
						}
					}
					else
					{
						il.Call(m);
					}

					Transform.GetMetaConversion(m.ReturnType, il);
					il.CastClass(typeof(Map));
					il.Return();
					_caller = (Caller)il.GetDelegate(obj);

				}
				return _caller;
			}
		}
		Emitter il;

		public Type type;
		public Method(MethodBase method, object obj, Type type, MemberInfo original)
		{
			this.type = type;
			this.method = method;
			this.obj = obj;

			this.parameters = method.GetParameters();
			this.original = original;
			if (method.IsConstructor)
			{
				this.returnType = method.ReflectedType;
			}
			else if (method.IsStatic)
			{
				this.returnType = ((MethodInfo)method).ReturnType;
				this.method = method;
			}
			else
			{
				this.returnType = ((MethodInfo)method).ReturnType;
				//MethodInfo m = (MethodInfo)method;
				//ParameterInfo[] pars = method.GetParameters();

				//il = new Emitter(typeof(Caller), obj.GetType());
				//if (type.IsValueType)
				//{
				//    LocalBuilder local = il.DeclareLocal(type);
				//    il.LoadArgument(0);
				//    il.UnboxAny(type);
				//    il.StoreLocal(local);
				//    il.LoadLocalAddress(local);
				//}
				//else
				//{
				//    il.LoadArgument(0);
				//}

				//for (int i = 0; i < pars.Length; i++)
				//{
				//    il.LoadArgument(1);
				//    il.LoadElement(i);
				//    il.CastClass(typeof(Map));
				//    Transform.GetDotNetConversion(pars[i].ParameterType, il);
				//}
				//if (obj.GetType() != type || type.IsValueType)
				//{
				//    if (type.IsValueType && method.IsVirtual)
				//    {
				//        il.Constrained(type);
				//        il.Call(m);

				//    }
				//    else
				//    {
				//        il.CallNonVirtual(m);
				//    }
				//}
				//else
				//{
				//    il.Call(m);
				//}

				//Transform.GetMetaConversion(m.ReturnType, il);
				//il.CastClass(typeof(Map));
				//il.Return();
				//caller = (Caller)il.GetDelegate(obj);
			}
			//this.metaConversion = Transform.GetMetaConversion(returnType);
			//foreach (ParameterInfo parameter in parameters)
			//{
			//    if (parameter.ParameterType == typeof(Int16))
			//    {
			//    }
			//    conversions.Add(Transform.GetDotNetConversion(parameter.ParameterType));
			//}
		}
		private List<DotNetConversion> conversions
		{
			get
			{
				if (_conversions == null)
				{
					_conversions = new List<DotNetConversion>();
					foreach (ParameterInfo parameter in parameters)
					{
						_conversions.Add(Transform.GetDotNetConversion(parameter.ParameterType));
					}
				}
				return _conversions;
			}
		}
		private List<DotNetConversion> _conversions;
		private MetaConversion metaConversion
		{
			get
			{
				if (_metaConversion == null)
				{
					this._metaConversion = Transform.GetMetaConversion(returnType);
				}
				return _metaConversion;
			}
		}
		private MetaConversion _metaConversion;
		public ParameterInfo[] parameters;
		public override Map Call(Map argument)
		{
			return DecideCall(argument, new List<Map>());
		}
		private Map DecideCall(Map argument, List<Map> oldArguments)
		{

			List<Map> arguments = new List<Map>(oldArguments);
			if (parameters.Length != 0)
			{
				arguments.Add(argument);
			}
			if (arguments.Count >= parameters.Length)
			{
				return Invoke(argument, arguments.ToArray());
			}
			else
			{
				return new PartiallyAppliedMethod(this, arguments.ToArray());
			}
		}
		Type returnType;
		MethodInfo invokeMethod = typeof(CallDelegate).GetMethod("Invoke");
		private object[] ConvertParameters(Map[] args)
		{
			object[] list = new object[args.Length];;
			for (int i = 0; i < args.Length; i++)
			{
				list[i]=conversions[i](args[i]);
			 }
			return list;
		}
		// TODO: remove 'argument'
		public Map Invoke(Map argument, Map[] arguments)
		{
			object result;
			if (method is ConstructorInfo)
			{
				if (Interpreter.simulate)
				{
					if (method != null)
					{
						return new ObjectMap(null, method.DeclaringType);
					}
					return new DictionaryMap();
				}
				result = ((ConstructorInfo)method).Invoke(ConvertParameters(arguments));
			}
			else if (method.IsStatic)
			{
				if (Interpreter.simulate && method.DeclaringType != typeof(Library))
				{
					MethodInfo m = (MethodInfo)method;
					if (method != null && m.ReturnType != typeof(void))
					{
						if (m.ReturnType.IsPrimitive)
						{
							return new DictionaryMap();
						}
						return new ObjectMap(null, m.ReturnType);
					}
					return new DictionaryMap();
				}
				object[] param = ConvertParameters(arguments);
                try
                {
                    result = method.Invoke(null, param);
                }
                catch (TargetInvocationException e)
                {
                    throw e.InnerException;
                }

				// TODO: optimize this
				Map r = null;
				int i = 0;
				foreach (ParameterInfo parameter in parameters)
				{
					if (parameter.IsOut)
					{
						if (r == null)
						{
							r = new DictionaryMap();
						}
						r[parameter.Name] = Transform.ToMeta(param[i]);
					}
					i++;
				}
				if (r!=null && r.Count != 0)
				{
					r["return"] = Transform.ToMeta(result);
					return r;
				}
			}
			else
			{
				// TODO: refactor
				if (Interpreter.simulate && (original == null || original.DeclaringType != typeof(Library)))
				{
					MethodInfo m = (MethodInfo)method;
					if (method != null && m.ReturnType != typeof(void))
					{
						if (m.ReturnType.IsPrimitive)
						{
							return new DictionaryMap();
						}
						return new ObjectMap(null, m.ReturnType);
					}
					return new DictionaryMap();
				}
				try
				{
					return (Map)CallerMethod(arguments);
				}
				catch
				{
					return (Map)CallerMethod(arguments);
				}
			}
			if (result == null)
			{
				return EmptyMap.Empty;
			}
			else
			{
				return metaConversion(result);
			}
		}
	}
	public class PartiallyAppliedMethod : ScopeMap
	{
		public override Map Copy()
		{
			return this;
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override bool ContainsKey(Map key)
		{
			return false;
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override int Count
		{
			get
			{
				return 0;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				yield break;
			}
		}
		public override Map Call(Map argument)
		{
			Map[] arguments;
			
			if(method.parameters.Length==0)
			{
				arguments=new Map[]{};
			}
			else
			{
				arguments = new Map[oldArguments.Length + 1];
				System.Array.Copy(oldArguments, arguments, oldArguments.Length);
				arguments[arguments.Length - 1] = argument;
			}
			//if (method.parameters.Length != 0)
			//{
			//    arguments.Add(argument);
			//}
			if (arguments.Length >= method.parameters.Length)
			{
				return method.Invoke(argument, arguments);
			}
			else
			{
				return new PartiallyAppliedMethod(this.method, arguments);
			}
		}
		public override Map this[Map key]
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}
		private Map[] oldArguments;
		public Method method;
		public PartiallyAppliedMethod(Method method, Map[] arguments)
		{
			this.method = method;
			this.oldArguments = arguments;
		}
	}
	public class PropertyMember : Member
	{
		public override MemberInfo Original
		{
			get
			{
				return property;
			}
		}
		public PropertyInfo property;
		public Type type;
		public PropertyMember(PropertyInfo property, Type type)
		{
			this.type = type;
			this.property = property;
		}
		public override void Set(object obj, Map value)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override Map Get(object obj)
		{
			return new PropertyMap(property, obj, type);
		}
	}
	public class EventMember : Member
	{
		public override MemberInfo Original
		{
			get
			{
				return eventInfo;
			}
		}
		public EventInfo eventInfo;
		public Type type;
		public EventMember(EventInfo eventInfo, Type type)
		{
			this.type = type;
			this.eventInfo = eventInfo;
		}
		public override void Set(object obj, Map value)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override Map Get(object obj)
		{
			return new EventMap(eventInfo, obj, type);
		}
	}
	[Serializable]
	public class PropertyMap : DictionaryMap
	{
		public override Map Call(Map argument)
		{
			if (Interpreter.simulate)
			{
				return EmptyMap.Empty;
			}
			return new Method(
				argument == null ? property.GetGetMethod() : property.GetSetMethod(),
				obj,
				type,
				property
			).Call(argument);
		}
		public PropertyInfo property;
		private Type type;
		private object obj;
		public PropertyMap(PropertyInfo property, object obj, Type type)
		{
			this.property = property;
			this.obj = obj;
			this.type = type;
			MethodInfo getter = property.GetGetMethod();
			if (getter != null)
			{
				this["get"] = new Method(getter, obj, type, property);
			}
			MethodInfo setter = property.GetSetMethod();
			if (setter != null)
			{
				this["set"] = new Method(setter, obj, type, property);
			}
		}

	}
	[Serializable]
	public class EventMap : DictionaryMap
	{
		public override Map Call(Map argument)
		{
			throw new Exception("Cannot call .NET event.");
		}
		public EventInfo eventInfo;
		private Type type;
		private object obj;
		public EventMap(EventInfo eventInfo, object obj, Type type)
		{
			this.eventInfo = eventInfo;
			this.obj = obj;
			this.type = type;
			MethodInfo adder = eventInfo.GetAddMethod();
			if (adder != null)
			{
				this["add"] = new Method(adder, obj, type, eventInfo);
			}
		}
	}
	// TODO: rename
	public class Versions
	{
		static Versions()
		{
			var file=Parser.Parse(Interpreter.LibraryPath);
			Map x = new DictionaryMap();
			// TODO: clean up
			x["gac"] = Gac.gac;
			file.Scope = x;
			file["gac"]=Gac.gac;


			versions= file.Call(EmptyMap.Empty);
			Gac.gac["library"]=versions;
			file["gac"] = null;
			//versions.Scope = Gac.gac; // ??
			versions["gac"] = Gac.gac;//.Scope = Gac.gac;
		}
		public static Map versions;
		//public static Map versions = new DirectoryMap(Interpreter.LibraryPath);
	}
	[Serializable]
	public abstract class Expression:ScopeMap
	{
		public Expression Optimize()
		{
			foreach (Expression e in Children)
			{
				e.Parent = this;
			}
			return OptimizeImplementation();
		}
		public Map EvaluateTest(Map context)
		{
			return Evaluate(ref context);
		}
		public abstract Map Key
		{
			get;
		}
		public override Map Copy(Map scope)
		{
			return this;
		}
		public override Meta.Map this[Meta.Map key]
		{
			get
			{
				if (key.Equals(Key))
				{
					return code;
				}
				return null;
			}
			set
			{
				throw new NotImplementedException();
			}
		}
		public override IEnumerable<Map> Keys
		{
			get 
			{
				yield return Key;
			}
		}
		public override IEnumerable<Map> Array
		{
			get 
			{
				yield break;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override int Count
		{
			get
			{
				return 1;
			}
		}
		public override bool ContainsKey(Map key)
		{
			return key.Equals(Key);
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override Map Copy()
		{
			// TODO: is this correct?
			return this;
		}
		public Program GetParentProgram()
		{
			Expression e=this;
			while (e != null)
			{
				if (e.Statement != null)
				{
					Program p = (Program)e.Statement.Scope.GetExpression();
					if (p == null && e.Statement.Scope.Scope!=null)
					{
						p = (Program)e.Statement.Scope.Scope.GetExpression();
					}
					return p;
				}
				e = e.Parent;
			}
			return null;
		}
		public virtual IEnumerable<Expression> Children
		{
			get
			{
				return new Expression[0];
			}
		}
		protected virtual Expression OptimizeImplementation()
		{
			return this;
		}
		public static List<Expression> expressions = new List<Expression>();
		public delegate Expression Optimization(Expression expression);
		private Expression parent;
		public Expression Parent
		{
			get
			{
				return parent;
			}
			set
			{
				parent = value;
			}
		}
		public Expression(Map map)
		{
			this.code = map;
			this.Source = code.Source;
			if (this.Source == null)
			{
			}
		}
		//[Ignore]
		//public Extent Source
		//{
		//    get
		//    {
		//        if (source == null)
		//        {
		//            source = code.Source;
		//        }
		//        return source;
		//    }
		//    set
		//    {
		//        source = value;
		//    }
		//}
		//private Extent source;
		[Ignore]
		public Map code;

		private Statement statement;
		// TODO: refactor
		[Ignore]
		public Statement Statement
		{
			get
			{
				return statement;
			}
			set
			{
				this.statement = value;
				if (statement!=null &&  statement.Parent != null)
				{
					this.Parent = statement.Parent;
				}
			}
		}
		public virtual Map Call(Map argument, Map scope)
		{
			return Evaluate(ref scope);
		}
		private Source breakpoint;
		public Source BreakPoint
		{
			get
			{
				return breakpoint;
			}
			set
			{
				breakpoint = value;
			}
		}
		public delegate void BreakPointEvent(Expression expression, Map context);
		public static event BreakPointEvent OnBreakPoint;

		public override Map Evaluate(ref Map context)
		{
			if (breakpoint != null)
			{
				if (OnBreakPoint != null)
				{
					OnBreakPoint(this, context);
				}
			}
			return EvaluateImplementation(ref context);
		}
		protected abstract Map EvaluateImplementation(ref Map context);
		public static Dictionary<Source, List<Expression>> sources = new Dictionary<Source, List<Expression>>();
	}
	[Serializable]
	public class LastArgument : Expression
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get
			{
				return CodeKeys.LastArgument;
			}
		}
		protected override Map EvaluateImplementation(ref Map context)
		{
			if (Interpreter.simulate && Map.arguments.Count == 0)
			{
				return new DictionaryMap();
			}
			else
			{
				Map result=Map.arguments[Map.arguments.Count -1];

				// TODO: fix this, refactor
				if (count != 0)
				{
					result = context;
					for (int i = 0; i < count; i++)
					{
						foreach (var a in result.Scope)
						{
							result = a.Value;
							break;
						}
					}
				}
				return result;
				//return Map.arguments.Peek();
			}
		}
		//protected override Map EvaluateImplementation(ref Map context)
		//{
		//    if (Interpreter.simulate && Map.arguments.Count == 0)
		//    {
		//        return new DictionaryMap();
		//    }
		//    else
		//    {
		//        return Map.arguments.Peek();
		//    }
		//}
		private int count;
		public LastArgument(Map code)
			: base(code)
		{
			this.count=code.GetInteger().GetInt32();
		}
	}
	public delegate Map InvokerDelegate(Expression[] calls, ref Map context);
	//[Serializable]
	//public class CompleteMethodCall : Call
	//{
	//    protected override Expression OptimizeImplementation()
	//    {
	//        return this;
	//    }
	//    public override Call GetCall()
	//    {
	//        return this.multiCall.call;
	//    }
	//    protected override Map EvaluateImplementation(ref Map context)
	//    {
	//        if (invoker != null)
	//        {
	//            return invoker(multiCall.calls, ref context);
	//        }
	//        else
	//        {
	//            Map[] arguments = new Map[multiCall.calls.Length - 1];
	//            for (int i = 1; i < multiCall.calls.Length; i++)
	//            {
	//                arguments[i - 1] = multiCall.calls[i].Evaluate(ref context);
	//            }
	//            return method.Invoke(null, arguments);
	//        }
	//    }
	//    public override Expression CreateExpression()
	//    {
	//        return this;
	//    }
	//    private Emitter il;
	//    private InvokerDelegate invoker;
	//    private MultiCall multiCall;
	//    Method method;
	//    public InvokerDelegate GetInvoker()
	//    {
	//        Emitter il = new Emitter(typeof(InvokerDelegate),typeof(CompleteMethodCall));
	//        ParameterInfo[] parameters = method.method.GetParameters();

	//        for (int i = 1; i < multiCall.calls.Length; i++)
	//        {
	//            il.LoadArgument(1);
	//            il.LoadElement(i);
	//            il.LoadArgument(2);
	//            il.Call(typeof(Expression), "Evaluate");
	//            Transform.GetDotNetConversion(parameters[i - 1].ParameterType, il);
	//            il.CastClass(typeof(Map));
	//        }
	//        il.Call((MethodInfo)method.method);

	//        Transform.GetMetaConversion(((MethodInfo)method.method).ReturnType, il);
	//        il.CastClass(typeof(Map));
	//        il.Return();
	//        this.il = il;

	//        return (InvokerDelegate)il.GetDelegate(this);
	//    }

	//    public CompleteMethodCall(MultiCall code,Method method)
	//        : base(code.call.function, code.call.argument)
	//    {
	//        this.multiCall = code;
	//        this.method = method;
	//        // TODO: make this more general?
	//        if (method.method is MethodInfo && (method.method.Name == "Multiply" || method.method.Name == "Subtract" || method.method.Name == "Equal" || method.method.Name == "Apply"))
	//        {
	//            this.invoker = GetInvoker();
	//        }
	//    }
	//    public override Map Key
	//    {
	//        get
	//        {
	//            return CodeKeys.Call;
	//        }
	//    }
	//}
	[Serializable]
	public class MultiCall : Expression
	{
		protected override Expression OptimizeImplementation()
		{
			Literal literal = calls[0].GetLiteral();
			//if (literal != null)
			//{
			//    Method method=literal.literal as Method;
			//    if (method != null && method.parameters.Length == this.calls.Length - 1)
			//    {
			//        return new CompleteMethodCall(this,method);
			//    }
			//}
			return this;
		}
		public override Call GetCall()
		{
			return this.call;
		}
		protected override Map EvaluateImplementation(ref Map context)
		{
			Map result = calls[0].Evaluate(ref context);
			for (int i = 1; i < calls.Length || i == 1; i++)
			{
				//try
				//{
					if (!Interpreter.simulate || result is Method || (result is TypeMap) || (result is Method && ((Method)result).method.DeclaringType == typeof(Library) || (result is Method && ((Method)result).original != null && ((Method)result).original.DeclaringType == typeof(Library))) || (result.Scope != null && result.Scope.Scope is DirectoryMap) || result is DictionaryMap)
					{
						Map arg;
						if (calls.Length == 1)
						{
							arg = new DictionaryMap();
						}
						else
						{
							arg = calls[i].Evaluate(ref context);
						}
						result = result.Call(arg);
					}
					else
					{
						return new DictionaryMap();
					}
				//}
				//catch (MetaException e)
				//{
				//    e.InvocationList.Add(new ExceptionLog(Source!=null?Source.Start:null));
				//    throw e;
				//}
				//catch (Exception e)
				//{
				//    while (e.InnerException != null)
				//    {
				//        e = e.InnerException;
				//    }
				//    throw new MetaException(e.Message + "\n" + e.StackTrace, Source.Start);
				//}
			}
			return result;
		}
		public override Expression CreateExpression()
		{
			return this;
		}
		public Expression[] calls;
		public Call call;
		public MultiCall(Call code):base(code)
		{
			this.call = code;
			List<Expression> callsList = new List<Expression>();
			Call c = code;
			while (true)
			{
				callsList.Add(c.argument);
				Call sub=c.function.GetCall();
				if (sub != null)
				{
					c = sub;
				}
				else
				{
					callsList.Add(c.function);
					break;
				}
			}
			callsList.Reverse();
			calls = callsList.ToArray();
		}
		public override Map Key
		{
			get 
			{
				return CodeKeys.Call;
			}
		}
	}
	// TODO: Should CompleteMethodCall be a sublcass?
	[Serializable]
	public class Call : Expression
	{
		public override Call GetCall()
		{
			return this;
		}
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get
			{
				return CodeKeys.Call;
				//return CodeKeys.Key;
			}
		}
		protected override Expression OptimizeImplementation()
		{
			function = function.Optimize().Optimize();
			argument = argument.Optimize().Optimize();

			this.code.Scope.Expression = this;
			Call c = function.GetCall();
			if (c != null)
			{
				return new MultiCall(this);
			}
			return this;
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				yield return function;
				yield return argument;
			}
		}
		public Expression function;
		public Expression argument;
		public Call(Map first, Map second)
			: base(new DictionaryMap(1, first, 2, second))
		{
			this.code.Scope = this;
			this.function = first.GetExpression();
			this.argument = second.GetExpression();
			this.function.Scope = this;
			this.argument.Scope = this;
			this.function.Parent = this;
			this.argument.Parent = this;
		}
		public Call(Map code)
			: base(code)
		{
			// TODO: remove this
			throw new NotImplementedException();
		}
		protected override Map EvaluateImplementation(ref Map context)
		{
			//try
			//{
			Map result = function.Evaluate(ref context);
			if (!Interpreter.simulate || result is Method || (result is TypeMap) || (result is Method && ((Method)result).method.DeclaringType == typeof(Library) || (result is Method && ((Method)result).original != null && ((Method)result).original.DeclaringType == typeof(Library))) || (result is Method && ((Method)result).method.DeclaringType == typeof(Library) || (result is PartiallyAppliedMethod && ((PartiallyAppliedMethod)result).method.original != null && ((PartiallyAppliedMethod)result).method.original.DeclaringType == typeof(Library))) || (result.Scope != null && result.Scope.Scope is DirectoryMap) || result is DictionaryMap)
			{
				return result.Call(argument.Evaluate(ref context));
			}
			else
			{
				return new DictionaryMap();
			}
			//}
			//catch (MetaException e)
			//{
			//    e.InvocationList.Add(new ExceptionLog(Source!=null?Source.Start:null));
			//    throw e;
			//}
			//catch (Exception e)
			//{
			//    while (e.InnerException != null)
			//    {
			//        e = e.InnerException;
			//    }
			//    throw new MetaException(e.Message + "\n" + e.StackTrace, Source.Start);
			//}
		}
	}
	//[Serializable]
	//public class Call : Expression
	//{
	//    public override Call GetCall()
	//    {
	//        return this;
	//    }
	//    public override Expression CreateExpression()
	//    {
	//        return this;
	//    }
	//    public override Map Key
	//    {
	//        get
	//        {
	//            return CodeKeys.Call;
	//            //return CodeKeys.Key;
	//        }
	//    }
	//    protected override Expression OptimizeImplementation()
	//    {
	//        function = function.Optimize().Optimize();
	//        argument = argument.Optimize().Optimize();

	//        this.code.Scope.Expression = this;
	//        Call c = function.GetCall();
	//        if (c != null)
	//        {
	//            return new MultiCall(this);
	//        }
	//        return this;
	//    }
	//    public override IEnumerable<Expression> Children
	//    {
	//        get
	//        {
	//            yield return function;
	//            yield return argument;
	//        }
	//    }
	//    public Expression function;
	//    public Expression argument;
	//    public Call(Map first, Map second)
	//        : base(new DictionaryMap(1, first, 2, second))
	//    {
	//        this.code.Scope = this;
	//        this.function = first.GetExpression();
	//        this.argument = second.GetExpression();
	//        this.function.Scope = this;
	//        this.argument.Scope = this;
	//        this.function.Parent = this;
	//        this.argument.Parent = this;
	//    }
	//    public Call(Map code)
	//        : base(code)
	//    {
	//        // TODO: remove this
	//        throw new NotImplementedException();
	//    }
	//    protected override Map EvaluateImplementation(ref Map context)
	//    {
	//        //try
	//        //{
	//            Map result = function.Evaluate(ref context);
	//            if (!Interpreter.simulate || result is Method || (result is TypeMap) || (result is Method && ((Method)result).method.DeclaringType == typeof(Library) || (result is Method && ((Method)result).original != null && ((Method)result).original.DeclaringType == typeof(Library))) || (result is Method && ((Method)result).method.DeclaringType == typeof(Library) || (result is PartiallyAppliedMethod && ((PartiallyAppliedMethod)result).method.original != null && ((PartiallyAppliedMethod)result).method.original.DeclaringType == typeof(Library))) || (result.Scope != null && result.Scope.Scope is DirectoryMap) || result is DictionaryMap)
	//            {
	//                return result.Call(argument.Evaluate(ref context));
	//            }
	//            else
	//            {
	//                return new DictionaryMap();
	//            }
	//        //}
	//        //catch (MetaException e)
	//        //{
	//        //    e.InvocationList.Add(new ExceptionLog(Source!=null?Source.Start:null));
	//        //    throw e;
	//        //}
	//        //catch (Exception e)
	//        //{
	//        //    while (e.InnerException != null)
	//        //    {
	//        //        e = e.InnerException;
	//        //    }
	//        //    throw new MetaException(e.Message + "\n" + e.StackTrace, Source.Start);
	//        //}
	//    }
	//}
	[Serializable]
	public class Search : Expression
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get 
			{
				return CodeKeys.Search;
			}
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				return new Expression[] { expression };
			}
		}
		public static readonly StringMap Meta = new StringMap("Meta");
		protected override Expression OptimizeImplementation()
		{
			Literal key = this.expression as Literal;
			if (key != null)
			{
				Program parent = this.GetParentProgram();
				while (true)
				{
					// TODO: fix parent being null
					if (parent!=null && parent.HasOnlyLiteralKeys() && !parent.GetLiteralKeys().ContainsKey(key.literal))
					{
						if (parent.Statement == null)
						{
							parent = null;
						}
						else
						{
							parent = parent.GetParentProgram();
						}
					}
					else
					{
						break;
					}
					if (parent == null)
					{
						// TODO: create FixedLocationSearch optimization
						if (Versions.versions.ContainsKey(key.literal))
						{
							return new Literal(Versions.versions[key.literal]);
						}
						// TODO: fix Gac.ContainsKey method
						else if (key.literal.Equals(Meta))// Gac.gac.ContainsKey(key.literal))
						{
							return new Literal(Gac.gac[key.literal]);
						}
						else
						{
							break;
						}
					}
				}
			}
			return this;
		}
		public static Dictionary<Map, int> search = new Dictionary<Map, int>();
		public Expression expression;
		public Search(Map code)
			: base(code)
		{
			this.expression = code.GetExpression();
			this.expression.Parent = this;
		}

		protected override Map EvaluateImplementation(ref Map context)
		{
			Map k = expression.Evaluate(ref context);
			Map selected = context;
			while (!selected.ContainsKey(k))
			{
				if (selected.Scope != null)
				{
					selected = selected.Scope;
				}
				else
				{
					if (Interpreter.simulate)
					{
						return new DictionaryMap();
					}
					else
					{
						throw new KeyNotFound(k, Source.Start, k);
					}
				}
			}
			return selected[k];
		}
	}
	// TODO: implement optimizations for nested functions (functions with multiple parameters)
	[Serializable]
	public class FunctionProgram: Program
	{
		protected override Map EvaluateImplementation(ref Map c)
		{
			Map context = new SingleEntryMap();
			context.Scope = c;
			int index = 0;
			foreach (Statement statement in statementList)
			{
				statement.Assign(ref context,index);
				index++;
			}
			return context;
		}
		public CurrentStatement CurrentStatement
		{
			get
			{
				return (CurrentStatement)statementList[1];
			}
		}
		public KeyStatement KeyStatement
		{
			get
			{
				return (KeyStatement)statementList[0];
			}
		}
		public FunctionProgram(Map code)
			: base(code)
		{
		}
		public static int counter = 0;
		protected override Expression OptimizeImplementation()
		{
			foreach (Statement statement in statementList)
			{
				statement.Optimize();
			}
			return this;
		}
	}
	[Serializable]
	public class SingleKeyProgram : Program
	{
		protected override Map EvaluateImplementation(ref Map c)
		{
			Map context = new SingleEntryMap();
			context.Scope = c;
			int index = 0;
			foreach (Statement statement in statementList)
			{
				statement.Assign(ref context,index);
				index++;
			}
			return context;
		}
		public SingleKeyProgram(Map code)
			: base(code)
		{
		}
		protected override Expression OptimizeImplementation()
		{
			// TODO: fix this
			return this;
			KeyStatement keyStatement = ((KeyStatement)statementList[0]);
			if (keyStatement.value is LastArgument && keyStatement.key is Literal)
			{
				Expression p = new FunctionProgram(code);
				p = p.Optimize();
				return p;
			}
			foreach (Statement statement in statementList)
			{
				statement.Optimize();
			}
			return this;
		}
		//protected override Expression OptimizeImplementation()
		//{
		//    KeyStatement keyStatement=((KeyStatement)statementList[0]);
		//    if (keyStatement.value is LastArgument && keyStatement.key is Literal)
		//    {
		//        Expression p=new FunctionProgram(code);
		//        p = p.Optimize();
		//        return p;
		//    }
		//    foreach (Statement statement in statementList)
		//    {
		//        statement.Optimize();
		//    }
		//    return this;
		//}
	}
	[Serializable]
	public class Program : Expression
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get 
			{
				return CodeKeys.Program;
			}
		}
		protected override Expression OptimizeImplementation()
		{
			if (statementList.Count == 2)
			{
				KeyStatement keyStatement=statementList[0] as KeyStatement;
				CurrentStatement currentStatement = statementList[1] as CurrentStatement;
				if (keyStatement != null && currentStatement != null)
				{
					Expression program=new SingleKeyProgram(this.code);
					program = program.Optimize();
					return program;
				}

			}
			foreach (Statement statement in statementList)
			{
				statement.Optimize();
			}
			return this;
		}
		private Dictionary<Map,int> literalKeys;
		public Dictionary<Map,int> GetLiteralKeys()
		{
			if (literalKeys == null && HasOnlyLiteralKeys())
			{
				literalKeys = new Dictionary<Map,int>();
				for (int i = 0; i < statementList.Count; i++)
				{
					KeyStatement keyStatement = statementList[i] as KeyStatement;
					if (keyStatement != null)
					{
						Literal key = keyStatement.key as Literal;
						if (key != null)
						{
							literalKeys[key.literal] = 0;
						}
					}
				}
			}
			return literalKeys;
		}
		bool? literalKeysOnly;
		public bool HasOnlyLiteralKeys()
		{
			if (literalKeysOnly == null)
			{
				literalKeysOnly = true;
				for (int i = 0; i < statementList.Count; i++)
				{
					KeyStatement keyStatement = statementList[i] as KeyStatement;
					if (keyStatement != null)
					{
						Literal key = keyStatement.key as Literal;
						if (key != null)
						{
							continue;
						}
					}
					else if (i == statementList.Count - 1)
					{
						continue;
					}
					literalKeysOnly = false;
					break;
				}
			}
			return (bool)literalKeysOnly;
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				// TODO: fix this?
				yield break;
				//return this.statementList.Select(s => s.value).Union(this.statementList.Select(a => a as KeyStatement).Where(a => a != null).Select(a => a.key));
				//return this.statementList.Select(s => s.value).Union(this.statementList.Select(a => a as KeyStatement).Where(a => a != null).Select(a => a.key));
			}
		}
		public override Map Call(Map argument, Map scope)
		{
			Map result = Evaluate(ref scope);
			return result;
		}
		protected override Map EvaluateImplementation(ref Map c)
		{
			Map context;
			if (statementList.Count == 1)
			{
				context = new SingleEntryMap();
			}
			else
			{
				context = new DictionaryMap(statementList.Count);
			}
			context.Scope = c;
			int index = 0;
			foreach (Statement statement in statementList)
			{
				if (Interpreter.simulate)
				{
					if (Interpreter.stopStatements.Contains(statement))
					{
						return context;
					}
				}
				statement.Assign(ref context,index);
				index++;
			}
			return context;
		}
		public List<Statement> statementList = new List<Statement>();
		private bool CheckIsFunction()
		{
			if (statementList.Count == 2)
			{
				KeyStatement keyStatement = statementList[0] as KeyStatement;
				CurrentStatement currentStatement = statementList[1] as CurrentStatement;
				if (keyStatement != null && currentStatement != null && keyStatement.value is LastArgument)
				{
					Literal literal = keyStatement.key as Literal;
				}
			}
			return false;
		}
		public Program(Map code)
			: base(code)
		{
			int index = 0;
			foreach (Map m in code.Array)
			{
				Statement statement = m.GetStatement(code, index);
				statement.Parent = this;
				statementList.Add(statement);
				index++;
			}
		}
	}

	public delegate Map Compiled(Map map);

	public delegate Map MetaConversion(object obj);

	public delegate object DotNetConversion(Map map);

	public delegate void StatementDelegate(ref Map context, Map value);

	[Serializable]
	public abstract class Statement:ScopeMap
	{
		private Expression parent;
		public Expression Parent
		{
			get
			{
				return parent;
			}
			set
			{
				this.value.Parent = parent;
				parent = value;
			}
		}
		// TODO: fix this
		//public override Map Scope
		//{
		//    get
		//    {
		//        return base.Scope;
		//    }
		//    set
		//    {
		//        // TODO: fix this
		//        this.value.Parent = (Program)value;
		//        base.Scope = value;
		//    }
		//}
		public override Map Copy()
		{
			// TODO: is this correct?
			return this;
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override bool ContainsKey(Map key)
		{
			if (key.Equals(CodeKeys.Value))
			{
				return true;
			}
			return Key != null && key.Equals(Key);
		}
		public override int Count
		{
			get 
			{
				if (Key != null)
				{
					return 2;
				}
				return 1;
			}
		}
		public override int ArrayCount
		{
			get 
			{
				return 0;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		protected abstract Map Key
		{
			get;
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				yield return CodeKeys.Value;
				if (Key != null)
				{
					yield return Key;
				}
				yield break;
			}
		}
		public override Map this[Map key]
		{
			get
			{
				if (key.Equals(CodeKeys.Value))
				{
					return value;
				}
				else if (key.Equals(Key))
				{
					return GetKeyValue(key);
				}
				return null;
			}
			set
			{
				throw new NotImplementedException();
			}
		}
		protected abstract Map GetKeyValue(Map key);
		public void Optimize()
		{
			value.Statement = this;
			value = value.Optimize().Optimize();
			value.Statement=this;
			OptimizeKey();
		}
		protected abstract void OptimizeKey();
		public abstract void Assign(ref Map context,int index);
		public Expression value;
		public Statement(Expression value)
		{
			this.value = value;
			if (value != null)
			{
				value.Statement = this;
			}
		}
	}
	[Serializable]
	public class DiscardStatement : Statement
	{
		protected override Map GetKeyValue(Map key)
		{
			return null;
		}
		protected override Map Key
		{
			get
			{
				return null;
			}
		}
		protected override void OptimizeKey()
		{
		}
		public DiscardStatement(Map key, Expression value)
			: base(value)
		{
		}
		public override void Assign(ref Map context,int index)
		{
			value.Evaluate(ref context);
		}

	}
	[Serializable]
	public class KeyStatement : Statement
	{
		protected override Map GetKeyValue(Map key)
		{
			return this.key;
		}
		protected override Map Key
		{
			get
			{
				return CodeKeys.Key;
			}
		}
		protected override void OptimizeKey()
		{
			key = key.Optimize().Optimize();
			key.Statement = this;
		}
		public static bool intellisense = false;
		public override void Assign(ref Map context, int index)
		{
			context[key.Evaluate(ref context)] = value.Evaluate(ref context);
		}
		public Expression key;
		public KeyStatement(Expression key, Expression value)
			: base(value)
		{
			if (value == null)
			{
			}
			this.key = key;
			key.Statement = this;
		}
	}
	[Serializable]
	public class CurrentStatement : Statement
	{
		protected override Map GetKeyValue(Map key)
		{
			return null;
		}
		protected override Map Key
		{
			get 
			{
				return null;
			}
		}
		protected override void OptimizeKey()
		{
		}

		public override void Assign(ref Map context, int index)
		{
			Map v = value.Evaluate(ref context);
			// TODO: is this needed?
			if (index == 0)
			{
			 //TODO: fix this
				//if (!(v is DictionaryMap && context is DictionaryMap)&& !(v is StringMap))
				//{
				    Map scope = context.Scope;
				    context = v.Copy();
				    context.Scope = scope;
				//}
				//else
				//{
				//    context.CopyInternal(v);
				//}
				//context = v;
			}
			else
			{
			    context = v;
			}
		}
		public CurrentStatement(Map key, Expression value)
			: base(value)
		{
		}
	}
	[Serializable]
	public class SearchStatement : Statement
	{
		protected override Map GetKeyValue(Map key)
		{
			return this.key;
		}
		protected override Map Key
		{
			get 
			{
				return CodeKeys.Key;
			}
		}
		protected override void OptimizeKey()
		{
			key = key.Optimize().Optimize();
			key.Statement = this;
		}
		public override void Assign(ref Map context, int index)
		{
			Map v = value.Evaluate(ref context);
			Map selected = context;
			Map eKey = key.Evaluate(ref context);
			while (!selected.ContainsKey(eKey))
			{
				selected = selected.Scope;
				if (selected == null)
				{
					throw new KeyNotFound(eKey, key.Source.Start, null);
				}
			}
			selected[eKey] = v;
		}
		public Expression key;
		public SearchStatement(Expression key,Expression value)
			: base(value)
		{
			this.key = key;
			key.Statement = this;
		}
	}
	[Serializable]
	public class Literal : Expression
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get 
			{
				return CodeKeys.Literal;
			}
		}
		public bool? isExpression;
		public Expression expression;
		protected override Expression OptimizeImplementation()
		{
			if (isExpression == null)
			{
				Expression e = this.literal.GetExpression();
				if (e != null)
				{
					this.literal.Expression = this.literal.GetExpression().Optimize();
					this.expression = literal.Expression;
					isExpression = true;

					FunctionProgram program = expression as FunctionProgram;
					if (program != null)
					{
						Map arg = ((Literal)program.KeyStatement.key).literal;
						Call call = program.CurrentStatement.value as Call;
						if (call != null)
						{
							// TODO: make sure there are no other searches in subexpressions that refer to the parameter
							Search search = call.argument as Search;
							if (search != null)
							{
								Literal l = search.expression as Literal;
								if (l != null)
								{
									if (l.literal.Equals(arg))
									{
										Expression x = call.function;
										x = x.Optimize();
										return x;
									}
								}
							}
						}
					}
					expression = expression.Optimize();
					literal.Expression = expression;
				}
				else
				{
					isExpression = false;
				}


			}
			return this;
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				Expression e = literal.GetExpression();
				if (e != null)
				{
					e.Parent = this;
					return new Expression[] { e };
				}
				else
				{
					return new Expression[0];
				}
			}
		}
		private static Dictionary<Map, Map> cached = new Dictionary<Map, Map>();
		public Map literal;
		protected override Map EvaluateImplementation(ref Map context)
		{
			Map result = literal.Copy(context);
			return result;
		}
		public Literal(Map code)
			: base(code)
		{
			if (code == null)
			{
			}
			this.literal = code;
		}
	}
	[Serializable]
	public class LiteralTest : Expression
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get
			{
				return CodeKeys.Literal;
			}
		}
		public bool? isExpression;
		public Expression expression;
		protected override Expression OptimizeImplementation()
		{
			if (isExpression == null)
			{
				Expression e = this.literal.GetExpression();
				if (e != null)
				{
					this.literal.Expression = this.literal.GetExpression().Optimize();
					this.expression = literal.Expression;
					isExpression = true;
				}
				else
				{
					isExpression = false;
				}
			}
			return this;
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				Expression e = literal.GetExpression();
				if (e != null)
				{
					e.Parent = this;
					return new Expression[] { e };
				}
				else
				{
					return new Expression[0];
				}
			}
		}
		private static Dictionary<Map, Map> cached = new Dictionary<Map, Map>();
		public Map literal;
		protected override Map EvaluateImplementation(ref Map context)
		{
			Map result = literal.Copy(context);
			return result;
		}
		public LiteralTest(Map code)
			: base(code)
		{
			this.literal = code;
		}
	}
	[Serializable]
	public class Root : Expression
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		public override Map Key
		{
			get 
			{
				return CodeKeys.Root;
			}
		}
		public Root(Map code)
			: base(code)
		{
		}
		protected override Map EvaluateImplementation(ref Map context)
		{
			return Versions.versions;
		}
	}
	
	[Serializable]
	public class Select : Expression
	{
		public override Expression CreateExpression()
		{
			return new Select(this[CodeKeys.Select]);
		}
		public override Map Key
		{
			get
			{
				return CodeKeys.Select;
			}
		}
		
		protected override Expression OptimizeImplementation()
		{
			for(int i=0;i<subs.Count;i++)
			{
				subs[i] = subs[i].Optimize().Optimize();
				subs[i].Parent = this;
			}
			if (subs[0] is Literal && subs[1] is Literal)
			{
				Map key=((Literal)subs[1]).literal;
				Map map=((Literal)subs[0]).literal;
				Map value = map[key];
				if (value == null)
				{
					// TODO: add source
					throw new KeyDoesNotExist(key,null,map);
				}
				return new Literal(value);
			}
			Program program = subs[0] as Program;
			if (program != null)
			{
				if (program.statementList.Count == 2)
				{
					KeyStatement first = program.statementList[0] as KeyStatement;
					KeyStatement second = program.statementList[1] as KeyStatement;
					if (first != null && second != null)
					{
						Literal firstLiteral = first.key as Literal;
						Literal secondLiteral = second.key as Literal;
						if (firstLiteral != null && secondLiteral != null)
						{
							Expression e = new SwitchSelect(subs[0], subs[1], firstLiteral.literal, secondLiteral.literal, first.value, second.value);
							e.code = this.code;
							e.Parent = this.Parent;
							return e;
						}
					}
				}
			}
			return this;
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				return this.subs;
			}
		}
		protected override Map EvaluateImplementation(ref Map context)
		{
			Map selected = subs[0].Evaluate(ref context);
			for (int i = 1; i < subs.Count; i++)
			{
				Map key = subs[i].Evaluate(ref context);
				Map value = selected[key];
				if (value == null)
				{
					if (Interpreter.simulate)
					{
						return new DictionaryMap();
					}
					else
					{
						selected.ContainsKey(key);
						throw new KeyDoesNotExist(key, Source != null ? Source.Start : null, selected);
					}
				}
				selected = value;
			}
			return selected;
		}
		// TODO: remove this
		public List<Expression> subs = new List<Expression>();
		public Select(Expression first, Expression second):base(new DictionaryMap(1,first,2,second))// Map.Empty)
		{
			this.subs.Add(first);
			this.subs.Add(second);
			this.Source = new Extent(first.Source.Start,second!=null?second.Source.End:first.Source.End);
		}
		// TODO: Disallow more than 2 expressions in select
		public Select(Map code)
			: base(code)
		{
			foreach (Map m in code.Array)
			{
				Expression expression = m.GetExpression();
				expression.Parent = this;
				subs.Add(expression);
			}
			this.Source = new Extent(subs[0].Source.Start, subs.Count>1 ? subs[1].Source.End : subs[0].Source.End);
		}
	}
	public class SwitchSelect : Select
	{
		public override Expression CreateExpression()
		{
			return this;
		}
		protected override Expression OptimizeImplementation()
		{
			return this;
		}
		protected override Map EvaluateImplementation(ref Map context)
		{
			Map f = firstValue.Evaluate(ref context);
			Map s = secondValue.Evaluate(ref context);

			Map sub = this.subs[1].Evaluate(ref context);
			if (sub.Equals(firstLiteral))
			{
				return f;
			}
			else if (sub.Equals(secondLiteral))
			{
				return s;
			}
			else
			{
				throw new KeyDoesNotExist(sub, this.Source.Start, null);
			}
		}
		public override IEnumerable<Expression> Children
		{
			get
			{
				yield return firstValue;
				yield return secondValue;
			}
		}
		private Map firstLiteral;
		private Map secondLiteral;
		private Expression firstValue;
		private Expression secondValue;
		public SwitchSelect(Expression first, Expression second,Map firstLiteral,Map secondLiteral,Expression firstValue,Expression secondValue)
			: base(first, second)
		{
			this.firstLiteral = firstLiteral;
			this.secondLiteral = secondLiteral;
			this.firstValue = firstValue;
			this.secondValue = secondValue;
			for (int i = 0; i < subs.Count; i++)
			{
				subs[i] = subs[i].Optimize().Optimize();
				subs[i].Parent = this;
			}
		}
	}
	public delegate Map CallDelegate(Map argument);
	public class ExecutionException : MetaException
	{
		private Map context;
		public ExecutionException(string message, Source source, Map context)
			: base(message, source)
		{
			this.context = context;
		}
	}
	public class KeyDoesNotExist : ExecutionException
	{
		public KeyDoesNotExist(Map key, Source source, Map map)
			: base("Key does not exist: " + Serialization.Serialize(key) + " in " + Serialization.Serialize(map), source, map)
		{
		}
	}
	public class KeyNotFound : ExecutionException
	{
		public KeyNotFound(Map key, Source source, Map map)
			: base("Key not found: " + Serialization.Serialize(key), source, map)
		{
		}
	}
	public class Transform
	{
		public static object ConvertArrayToMeta(object obj)
		{
			//obj.GetType();
			// TODO: fix this

			//int i=1;
			List<Map> list = new List<Map>();
			foreach (var x in obj as string[])
			{
				list.Add(new StringMap(x));
				//m[i]=x;
				//i++;
			}
			return new ListMap(list);
		}
		//public static object ConvertArrayToMeta(object obj)
		//{
		//    //obj.GetType();
		//    // TODO: fix this
			
		//    //int i=1;
		//    List<Map> list=new List<Map>();
		//    foreach (var x in obj as string[])
		//    {
		//        list.Add(ToMeta(x));
		//        //m[i]=x;
		//        //i++;
		//    }
		//    return new ListMap(list);
		//}
		public static object ConvertArray(Map map,long typeToken)
		{
			Type arrayType = types[(IntPtr)typeToken];
			List<Map> array=new List<Map>(map.Array);
			Type type = arrayType.GetElementType();
			Array result=Array.CreateInstance(type, array.Count);
			for(int i=0;i<array.Count;i++)
			{
				result.SetValue(ToDotNet(array[i],type),i);
			}
			return result;
		}
		public static Dictionary<IntPtr, Type> types = new Dictionary<IntPtr, Type>();
		public static Delegate CreateDelegateFromCode(Map code, long typeToken)
		{
			Type type = types[(IntPtr)typeToken];
			return CreateDelegateFromCode(code, type);
		}
		public static Delegate CreateDelegateFromCode(Map code, Type delegateType)
		{
			MethodInfo invoke = delegateType.GetMethod("Invoke");
			ParameterInfo[] parameters = invoke.GetParameters();
			Emitter il = new Emitter(delegateType, typeof(Map));
			LocalBuilder current = il.DeclareLocal(typeof(Map));
			il.LoadArgument(0);
			il.StoreLocal(current);

			for (int i = 0; i < parameters.Length; i++)
			{
				il.LoadLocal(current);
				il.LoadArgument(i + 1);
				Transform.GetMetaConversion(parameters[i].ParameterType, il);
				il.Call(typeof(Map), "Call");
				il.StoreLocal(current);
			}

			if (invoke.ReturnType == typeof(void))
			{
				il.Return();
			}
			else
			{
				il.LoadLocal(current);
				Transform.GetDotNetConversion(invoke.ReturnType, il);
				il.Return();
			}
			return (Delegate)il.GetDelegate(code);
		}
		public static void GetMetaConversion(Type type, Emitter il)
		{
			Label end = il.DefineLabel();
			if (type.FullName.Contains("Keys"))
			{
			}
			if (type.Equals(typeof(void)))
			{
				il.NewObject(typeof(DictionaryMap));
			}
			else if (type.IsArray)
			{
				//IntPtr token = (IntPtr)target.TypeHandle.Value;
				//if (!Transform.types.ContainsKey(token))
				//{
				//    Transform.types[token] = target;
				//}
				//il.Emit(OpCodes.Ldc_I8, (long)token);
				il.Call(typeof(Transform), "ConvertArrayToMeta");
			}
			else if (!type.IsSubclassOf(typeof(Map)) && !type.Equals(typeof(Map)))
			{
				switch (Type.GetTypeCode(type))
				{
					case TypeCode.Boolean:
						il.Call(typeof(Convert), "ToInt32", typeof(Boolean));
						il.NewObject(typeof(Integer32), typeof(int));
						break;
					case TypeCode.Byte:
						il.Call(typeof(Convert), "ToInt32", typeof(Byte));
						il.NewObject(typeof(Integer32), typeof(int));
						break;
					case TypeCode.Char:
						il.Call(typeof(Convert), "ToInt32", typeof(Char));
						il.NewObject(typeof(Integer32), typeof(int));
						break;
					case TypeCode.SByte:
						il.Call(typeof(Convert), "ToInt32", typeof(SByte));
						il.NewObject(typeof(Integer32), typeof(int));
						break;
					case TypeCode.Single:
						il.NewObject(typeof(Rational), typeof(double));
						break;
					case TypeCode.UInt16:
						il.Call(typeof(Convert), "ToInt32", typeof(UInt16));
						il.NewObject(typeof(Integer32), new Type[] { typeof(int) });
						break;
					case TypeCode.UInt32:
						il.Call(typeof(Convert), "ToString", typeof(UInt32));
						il.NewObject(typeof(LargeInteger), typeof(string));
						break;
					case TypeCode.UInt64:
						il.Call(typeof(Convert), "ToString", typeof(UInt64));
						il.NewObject(typeof(LargeInteger), typeof(string));
						break;
					case TypeCode.String:
						il.NewObject(typeof(StringMap), typeof(string));
						break;
					case TypeCode.Decimal:
						il.Call(typeof(Convert), "ToDouble", typeof(Decimal));
						il.NewObject(typeof(Rational), typeof(double));
						break;
					case TypeCode.Double:
						il.NewObject(typeof(Rational), typeof(double));
						break;
					case TypeCode.Int16:
						il.Call(typeof(Convert), "ToInt32", typeof(Int16));
						il.NewObject(typeof(Integer32), typeof(int));
						break;
					case TypeCode.Int32:
						il.NewObject(typeof(Integer32), typeof(int));
						break;
					case TypeCode.Int64:
						il.Call(typeof(Convert), "ToString", typeof(Int64));
						il.NewObject(typeof(LargeInteger), typeof(string));
						break;
					case TypeCode.DateTime:
					case TypeCode.DBNull:
					case TypeCode.Object:
						if (type.Equals(typeof(void)))
						{
							il.LoadField(typeof(EmptyMap), "Empty");
						}
						else
						{
							if (!type.IsValueType)
							{
								Label label = il.DefineLabel();
								il.Duplicate();
								il.BranchTrue(label);
								il.Pop();
								il.LoadField(typeof(EmptyMap), "Empty");
								il.Break(end);
								il.MarkLabel(label);
							}
							if (type.IsValueType)
							{
								il.Box(type);
							}
							il.NewObject(typeof(ObjectMap), typeof(object));
						}
						break;
					default:
						throw new ApplicationException("Cannot convert object.");
				}
			}
			il.MarkLabel(end);
		}
		public static Dictionary<Type, MetaConversion> metaConversions = new Dictionary<Type, MetaConversion>();
		public static MetaConversion GetMetaConversion(Type type)
		{
			MetaConversion conversion;
			if (!metaConversions.TryGetValue(type, out conversion))
			{
				Emitter il = new Emitter(typeof(MetaConversion));
				il.LoadArgument(0);
				if (type.IsValueType)
				{
					il.UnboxAny(type);
				}
				GetMetaConversion(type, il);
				il.Return();
				conversion = (MetaConversion)il.GetDelegate();
				metaConversions[type] = conversion;
			}
			return conversion;
		}
		public static Map ToMeta(object dotNet)
		{
			if (dotNet == null)
			{
				return EmptyMap.Empty;
			}
			else
			{
				return GetMetaConversion(dotNet.GetType())(dotNet);
			}
		}
		// TODO: complete list of conversions
		public static bool GetDotNetConversion(Type target, Emitter il)
		{
			if (target.IsEnum)
			{
				IntPtr token = (IntPtr)target.TypeHandle.Value;
				if (!Transform.types.ContainsKey(token))
				{
					Transform.types[token] = target;
				}
				il.Call(typeof(Map), "GetInt32");
			}
			else if (target.Equals(typeof(double)))
			{
				il.Call(typeof(Map), "GetNumber");
				il.Call(typeof(Number), "GetDouble");
			}
			else if (target.Equals(typeof(Number)))
			{
				il.Duplicate();
				il.Call(typeof(Map), "GetNumber");
				il.Call(il.GetType(), "CheckConversionNullHelper");
			}
			else if (target.Equals(typeof(Map)))
			{
			}
			else if (target.Equals(typeof(Boolean)))
			{
				il.Call(typeof(Map), "GetInt32");
				il.Call(typeof(Convert), "ToBoolean", typeof(int));
			}
			else if (target.Equals(typeof(String)))
			{
				il.Call(typeof(Map), "GetString");
			}
			else if (target.Equals(typeof(int)) || target.Name == "Int32&")
			{
				il.Call(typeof(Map), "GetInt32");
			}
			else if (target.Equals(typeof(uint)))
			{
				il.Call(typeof(Map), "GetUInt32");
			}
			else if (target.Equals(typeof(long)))
			{
				// TODO: add error handling, CheckConversionNullHelper
				il.Call(typeof(Map), "GetNumber");
				il.Call(typeof(Number), "GetInteger64");
				il.LoadField(typeof(Integer64), "integer");
			}
			else if (target.Equals(typeof(Int16)))
			{
				il.Call(typeof(Map), "GetInt16");
			}
			// TODO: fix this
			else if (target.Equals(typeof(decimal)))
			{
				il.Call(typeof(Map), "GetNumber");
				il.Call(typeof(Number), "GetInteger64");
				il.LoadField(typeof(Integer64), "integer");
				il.Call(typeof(Convert), "ToDecimal", typeof(long));
			}
			else if (target.Equals(typeof(Single)))
			{
				il.Call(typeof(Map), "GetNumber");
				il.Call(typeof(Number), "GetSingle");
			}
			else if (target.Equals(typeof(char)))
			{
				il.Call(typeof(Map), "GetInteger");
				il.Call(typeof(Integer), "GetChar");
			}
			else if (target.IsArray)
			{
				IntPtr token = (IntPtr)target.TypeHandle.Value;
				if (!Transform.types.ContainsKey(token))
				{
					Transform.types[token] = target;
				}
				il.Emit(OpCodes.Ldc_I8, (long)token);
				il.Call(typeof(Transform), "ConvertArray");
			}
			else if (target.Equals(typeof(object)))
			{
				LocalBuilder local = il.DeclareLocal(typeof(ObjectMap));
				Label label = il.DefineLabel();
				il.Duplicate();
				il.IsInstance(typeof(ObjectMap));
				il.StoreLocal(local);
				il.LoadLocal(local);
				il.BranchFalse(label);
				il.Pop();
				il.LoadLocal(local);
				il.Call(typeof(ObjectMap), "get_Object");
				il.MarkLabel(label);
			}
			else if (target.Equals(typeof(Type)))
			{
				il.Call(typeof(Map), "GetClass");
			}
			else if ((target.IsSubclassOf(typeof(Delegate)) || target.Equals(typeof(Delegate))))
			{
				IntPtr token = (IntPtr)target.TypeHandle.Value;
				if (!Transform.types.ContainsKey(token))
				{
					Transform.types[token] = target;
				}
				il.Emit(OpCodes.Ldc_I8, (long)token);
				il.Call(typeof(Transform), "CreateDelegateFromCode", typeof(Map), typeof(long));
			}
			else
			{
				il.CastClass(typeof(ObjectMap));
				il.Call(typeof(ObjectMap), "get_Object");
				il.CastClass(target);
				if (target.IsValueType)
				{
					il.UnboxAny(target);
				}
			}
			return true;
		}
		public static Dictionary<Type, DotNetConversion> dotNetConversions = new Dictionary<Type, DotNetConversion>();
		public static DotNetConversion GetDotNetConversion(Type type)
		{
			DotNetConversion conversion;
			if (!dotNetConversions.TryGetValue(type, out conversion))
			{
				Emitter emitter = new Emitter(typeof(DotNetConversion));
				emitter.LoadArgument(0);
				GetDotNetConversion(type, emitter);
				if (type.IsValueType)
				{
					emitter.Box(type);
				}
				emitter.Return();
				conversion = (DotNetConversion)emitter.GetDelegate();
				dotNetConversions[type] = conversion;
			}
			return conversion;
		}
		public static object ToDotNet(Map meta, Type type)
		{
			return GetDotNetConversion(type)(meta);
		}
	}
	[Serializable]
	public class Emitter
	{
		public void MarkLabel(Label label)
		{
			il.MarkLabel(label);
		}
		public void Duplicate()
		{
			il.Emit(OpCodes.Dup);
		}
		public void BranchFalse(Label label)
		{
			il.Emit(OpCodes.Brfalse, label);
		}
		public void BranchTrue(Label label)
		{
			il.Emit(OpCodes.Brtrue, label);
		}
		public void Pop()
		{
			il.Emit(OpCodes.Pop);
		}
		public Label DefineLabel()
		{
			return il.DefineLabel();
		}
		public void Box(Type type)
		{
			il.Emit(OpCodes.Box, type);
		}
		public void StoreLocal(LocalBuilder local)
		{
			StoreLocal(local.LocalIndex);
		}
		public void StoreLocal(int index)
		{
			il.Emit(OpCodes.Stloc, index);
		}
		public void LoadLocalAddress(LocalBuilder local)
		{
			il.Emit(OpCodes.Ldloca, local);
		}
		public void LoadLocal(LocalBuilder local)
		{
			LoadLocal(local.LocalIndex);
		}
		public void LoadElement(int index)
		{
			il.Emit(OpCodes.Ldc_I4, index);
			il.Emit(OpCodes.Ldelem_Ref);
		}
		public void LoadLocal(int index)
		{
			il.Emit(OpCodes.Ldloc, index);
		}
		public void Break(Label label)
		{
			il.Emit(OpCodes.Br, label);
		}
		public void Emit(OpCode code, int operand)
		{
			il.Emit(code, operand);
		}
		public void Emit(OpCode code, long operand)
		{
			il.Emit(code, operand);
		}
		public LocalBuilder DeclareLocal(Type type)
		{
			return il.DeclareLocal(type);
		}
		public void Emit(OpCode code)
		{
			il.Emit(code);
		}
		public void BreakFalse(Label label)
		{
			il.Emit(OpCodes.Brfalse, label);
		}
		public void BreakTrue(Label label)
		{
			il.Emit(OpCodes.Brtrue, label);
		}
		public void Return()
		{
			il.Emit(OpCodes.Ret);
		}
		public void UnboxAny(Type type)
		{
			il.Emit(OpCodes.Unbox_Any, type);
		}
		public void NewArray(Type type)
		{
			il.Emit(OpCodes.Newarr, type);
		}
		public void LoadConstant(int i)
		{
			il.Emit(OpCodes.Ldc_I4, i);
		}
		public void LoadConstant(string s)
		{
			il.Emit(OpCodes.Ldstr, s);
		}
		public void NewObject(Type type)
		{
			NewObject(type, new Type[] { });
		}
		public void NewObject(Type type, params Type[] parameters)
		{
			NewObject(type.GetConstructor(parameters));
		}
		public void NewObject(ConstructorInfo constructor)
		{
			il.Emit(OpCodes.Newobj, constructor);
		}
		public void Emit(OpCode code, byte b)
		{
			il.Emit(code, b);
		}
		public void IsInstance(Type type)
		{
			il.Emit(OpCodes.Isinst, type);
		}
		public void CastClass(Type type)
		{
			il.Emit(OpCodes.Castclass, type);
		}
		public static object CheckConversionNullHelper(Map m,object x)
		{
			if (x == null)
			{
				throw new Exception("Failed to convert map to .NET object:"+m.ToString());
			}
			return x;
		}
		public void Call(Type type, string method)
		{
			Call(type.GetMethod(method));
		}
		public void Call(Type type, string method, params Type[] parameters)
		{
			Call(type.GetMethod(method, parameters));
		}
		public void CallNonVirtual(MethodInfo method)
		{
			il.Emit(OpCodes.Call, method);
		}
		public void Constrained(Type type)
		{
			il.Emit(OpCodes.Constrained, type);
		}
		public void Call(MethodInfo method)
		{
			il.Emit(
				method.IsStatic ?
					OpCodes.Call :
					OpCodes.Callvirt,
				method);
		}
		public void LoadField(Type type, string field)
		{
			LoadField(type.GetField(field));
		}
		public void LoadField(FieldInfo field)
		{
			il.Emit(
				field.IsStatic ?
					OpCodes.Ldsfld :
					OpCodes.Ldfld,
				field);
		}
		public void StoreElementReference()
		{
			il.Emit(OpCodes.Stelem_Ref);
		}
		public void LoadArgumentAddress(int index)
		{
			il.Emit(OpCodes.Ldarga, index);
		}
		public void LoadArgument(int index)
		{
			il.Emit(OpCodes.Ldarg, index);
		}
		public DynamicMethod dynamicMethod;
		public ILGenerator il;
		private Type type;
		public Emitter(ILGenerator il)
		{
			this.il = il;
		}
		public Emitter(Type type)
			: this(type, null)
		{
		}
		private Type instanceType;
		public Emitter(Type type, Type instance)
		{
			this.type = type;
			this.instanceType = instance;

			MethodInfo invoke = type.GetMethod("Invoke");
			var parameters = new List<Type>(new List<ParameterInfo>(invoke.GetParameters()).ConvertAll(delegate(ParameterInfo p) { return p.ParameterType; }));

			Type moduleType;
			if (instance != null)
			{
				if (instance.IsValueType)
				{
					parameters.Insert(0, typeof(object));
				}
				else
				{
					parameters.Insert(0, instance);
				}
				moduleType = instanceType;
			}
			else
			{
				moduleType = type;
			}
			this.dynamicMethod = new DynamicMethod("Whatever", invoke.ReturnType, parameters.ToArray(), moduleType.Module, true);
			il = dynamicMethod.GetILGenerator();
		}
		public object GetDelegate()
		{
			return dynamicMethod.CreateDelegate(type);
		}
		public object GetDelegate(object instance)
		{
			return dynamicMethod.CreateDelegate(type, instance);
		}
	}
	namespace Fusion
	{
		//-------------------------------------------------------------
		// Copyright Junfeng Zhang
		//
		// This implements managed wrappers to GAC API Interfaces
		//-------------------------------------------------------------

		//-------------------------------------------------------------
		// Interfaces defined by fusion
		//-------------------------------------------------------------
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")]
		internal interface IAssemblyCache
		{
			[PreserveSig()]
			int UninstallAssembly(
								int flags,
								[MarshalAs(UnmanagedType.LPWStr)]
							String assemblyName,
								InstallReference refData,
								out AssemblyCacheUninstallDisposition disposition);

			[PreserveSig()]
			int QueryAssemblyInfo(
								int flags,
								[MarshalAs(UnmanagedType.LPWStr)]
							String assemblyName,
								ref AssemblyInfo assemblyInfo);
			[PreserveSig()]
			int Reserved(
								int flags,
								IntPtr pvReserved,
								out Object ppAsmItem,
								[MarshalAs(UnmanagedType.LPWStr)]
							String assemblyName);
			[PreserveSig()]
			int Reserved(out Object ppAsmScavenger);

			[PreserveSig()]
			int InstallAssembly(
								int flags,
								[MarshalAs(UnmanagedType.LPWStr)]
							String assemblyFilePath,
								InstallReference refData);
		}// IAssemblyCache

		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CD193BC0-B4BC-11d2-9833-00C04FC31D2E")]
		internal interface IAssemblyName
		{
			[PreserveSig()]
			int SetProperty(
					int PropertyId,
					IntPtr pvProperty,
					int cbProperty);

			[PreserveSig()]
			int GetProperty(
					int PropertyId,
					IntPtr pvProperty,
					ref int pcbProperty);

			[PreserveSig()]
			int Finalize();

			[PreserveSig()]
			int GetDisplayName(
					StringBuilder pDisplayName,
					ref int pccDisplayName,
					int displayFlags);

			[PreserveSig()]
			int Reserved(ref Guid guid,
				Object obj1,
				Object obj2,
				String string1,
				Int64 llFlags,
				IntPtr pvReserved,
				int cbReserved,
				out IntPtr ppv);

			[PreserveSig()]
			int GetName(
					ref int pccBuffer,
					StringBuilder pwzName);

			[PreserveSig()]
			int GetVersion(
					out int versionHi,
					out int versionLow);
			[PreserveSig()]
			int IsEqual(
					IAssemblyName pAsmName,
					int cmpFlags);

			[PreserveSig()]
			int Clone(out IAssemblyName pAsmName);
		}// IAssemblyName

		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("21b8916c-f28e-11d2-a473-00c04f8ef448")]
		internal interface IAssemblyEnum
		{
			[PreserveSig()]
			int GetNextAssembly(
					IntPtr pvReserved,
					out IAssemblyName ppName,
					int flags);
			[PreserveSig()]
			int Reset();
			[PreserveSig()]
			int Clone(out IAssemblyEnum ppEnum);
		}// IAssemblyEnum

		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("582dac66-e678-449f-aba6-6faaec8a9394")]
		internal interface IInstallReferenceItem
		{
			// A pointer to a FUSION_INSTALL_REFERENCE structure. 
			// The memory is allocated by the GetReference method and is freed when 
			// IInstallReferenceItem is released. Callers must not hold a reference to this 
			// buffer after the IInstallReferenceItem object is released. 
			// This uses the InstallReferenceOutput object to avoid allocation 
			// issues with the interop layer. 
			// This cannot be marshaled directly - must use IntPtr 
			[PreserveSig()]
			int GetReference(
					out IntPtr pRefData,
					int flags,
					IntPtr pvReserced);
		}// IInstallReferenceItem

		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("56b1a988-7c0c-4aa2-8639-c3eb5a90226f")]
		internal interface IInstallReferenceEnum
		{
			[PreserveSig()]
			int GetNextInstallReferenceItem(
					out IInstallReferenceItem ppRefItem,
					int flags,
					IntPtr pvReserced);
		}// IInstallReferenceEnum

		public enum AssemblyCommitFlags
		{
			Default = 1,
			Force = 2
		}// enum AssemblyCommitFlags

		public enum AssemblyCacheUninstallDisposition
		{
			Unknown = 0,
			Uninstalled = 1,
			StillInUse = 2,
			AlreadyUninstalled = 3,
			DeletePending = 4,
			HasInstallReference = 5,
			ReferenceNotFound = 6
		}

		[Flags]
		internal enum AssemblyCacheFlags
		{
			GAC = 2,
		}

		internal enum CreateAssemblyNameObjectFlags
		{
			CANOF_DEFAULT = 0,
			CANOF_PARSE_DISPLAY_NAME = 1,
		}

		[Flags]
		internal enum AssemblyNameDisplayFlags
		{
			VERSION = 0x01,
			CULTURE = 0x02,
			PUBLIC_KEY_TOKEN = 0x04,
			PROCESSORARCHITECTURE = 0x20,
			RETARGETABLE = 0x80,
			// This enum will change in the future to include
			// more attributes.
			ALL = VERSION
										| CULTURE
										| PUBLIC_KEY_TOKEN
										| PROCESSORARCHITECTURE
										| RETARGETABLE
		}

		[StructLayout(LayoutKind.Sequential)]
		public class InstallReference
		{
			public InstallReference(Guid guid, String id, String data)
			{
				cbSize = (int)(2 * IntPtr.Size + 16 + (id.Length + data.Length) * 2);
				flags = 0;
				// quiet compiler warning 
				if (flags == 0) { }
				guidScheme = guid;
				identifier = id;
				description = data;
			}

			public Guid GuidScheme
			{
				get { return guidScheme; }
			}

			public String Identifier
			{
				get { return identifier; }
			}

			public String Description
			{
				get { return description; }
			}

			int cbSize;
			int flags;
			Guid guidScheme;
			[MarshalAs(UnmanagedType.LPWStr)]
			String identifier;
			[MarshalAs(UnmanagedType.LPWStr)]
			String description;
		}

		[StructLayout(LayoutKind.Sequential)]
		internal struct AssemblyInfo
		{
			public int cbAssemblyInfo; // size of this structure for future expansion
			public int assemblyFlags;
			public long assemblySizeInKB;
			[MarshalAs(UnmanagedType.LPWStr)]
			public String currentAssemblyPath;
			public int cchBuf; // size of path buf.
		}

		[ComVisible(false)]
		public class InstallReferenceGuid
		{
			public static bool IsValidGuidScheme(Guid guid)
			{
				return (guid.Equals(UninstallSubkeyGuid) ||
						guid.Equals(FilePathGuid) ||
						guid.Equals(OpaqueGuid) ||
						guid.Equals(Guid.Empty));
			}

			public readonly static Guid UninstallSubkeyGuid = new Guid("8cedc215-ac4b-488b-93c0-a50a49cb2fb8");
			public readonly static Guid FilePathGuid = new Guid("b02f9d65-fb77-4f7a-afa5-b391309f11c9");
			public readonly static Guid OpaqueGuid = new Guid("2ec93463-b0c3-45e1-8364-327e96aea856");
			// these GUID cannot be used for installing into GAC.
			public readonly static Guid MsiGuid = new Guid("25df0fc1-7f97-4070-add7-4b13bbfd7cb8");
			public readonly static Guid OsInstallGuid = new Guid("d16d444c-56d8-11d5-882d-0080c847b195");
		}

		[ComVisible(false)]
		public static class AssemblyCache
		{
			public static void InstallAssembly(String assemblyPath, InstallReference reference, AssemblyCommitFlags flags)
			{
				if (reference != null)
				{
					if (!InstallReferenceGuid.IsValidGuidScheme(reference.GuidScheme))
						throw new ArgumentException("Invalid reference guid.", "guid");
				}

				IAssemblyCache ac = null;

				int hr = 0;

				hr = Utils.CreateAssemblyCache(out ac, 0);
				if (hr >= 0)
				{
					hr = ac.InstallAssembly((int)flags, assemblyPath, reference);
				}

				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}
			}

			// assemblyName has to be fully specified name. 
			// A.k.a, for v1.0/v1.1 assemblies, it should be "name, Version=xx, Culture=xx, PublicKeyToken=xx".
			// For v2.0 assemblies, it should be "name, Version=xx, Culture=xx, PublicKeyToken=xx, ProcessorArchitecture=xx".
			// If assemblyName is not fully specified, a random matching assembly will be uninstalled. 
			public static void UninstallAssembly(String assemblyName, InstallReference reference, out AssemblyCacheUninstallDisposition disp)
			{
				AssemblyCacheUninstallDisposition dispResult = AssemblyCacheUninstallDisposition.Uninstalled;
				if (reference != null)
				{
					if (!InstallReferenceGuid.IsValidGuidScheme(reference.GuidScheme))
						throw new ArgumentException("Invalid reference guid.", "guid");
				}

				IAssemblyCache ac = null;

				int hr = Utils.CreateAssemblyCache(out ac, 0);
				if (hr >= 0)
				{
					hr = ac.UninstallAssembly(0, assemblyName, reference, out dispResult);
				}

				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}

				disp = dispResult;
			}

			// See comments in UninstallAssembly
			public static String QueryAssemblyInfo(String assemblyName)
			{
				if (assemblyName == null)
				{
					throw new ArgumentException("Invalid name", "assemblyName");
				}

				AssemblyInfo aInfo = new AssemblyInfo();

				aInfo.cchBuf = 1024;
				// Get a string with the desired length
				aInfo.currentAssemblyPath = new String('\0', aInfo.cchBuf);

				IAssemblyCache ac = null;
				int hr = Utils.CreateAssemblyCache(out ac, 0);
				if (hr >= 0)
				{
					hr = ac.QueryAssemblyInfo(0, assemblyName, ref aInfo);
				}
				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}

				return aInfo.currentAssemblyPath;
			}
		}

		[ComVisible(false)]
		public class AssemblyCacheEnum
		{
			// null means enumerate all the assemblies
			public AssemblyCacheEnum(String assemblyName)
			{
				IAssemblyName fusionName = null;
				int hr = 0;

				if (assemblyName != null)
				{
					hr = Utils.CreateAssemblyNameObject(
							out fusionName,
							assemblyName,
							CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME,
							IntPtr.Zero);
				}

				if (hr >= 0)
				{
					hr = Utils.CreateAssemblyEnum(
							out m_AssemblyEnum,
							IntPtr.Zero,
							fusionName,
							AssemblyCacheFlags.GAC,
							IntPtr.Zero);
				}

				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}
			}

			public String GetNextAssembly()
			{
				int hr = 0;
				IAssemblyName fusionName = null;

				if (done)
				{
					return null;
				}

				// Now get next IAssemblyName from m_AssemblyEnum
				hr = m_AssemblyEnum.GetNextAssembly((IntPtr)0, out fusionName, 0);

				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}

				if (fusionName != null)
				{
					return GetFullName(fusionName);
				}
				else
				{
					done = true;
					return null;
				}
			}

			private String GetFullName(IAssemblyName fusionAsmName)
			{
				StringBuilder sDisplayName = new StringBuilder(1024);
				int iLen = 1024;

				int hr = fusionAsmName.GetDisplayName(sDisplayName, ref iLen, (int)AssemblyNameDisplayFlags.ALL);
				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}

				return sDisplayName.ToString();
			}

			private IAssemblyEnum m_AssemblyEnum = null;
			private bool done;
		}// class AssemblyCacheEnum

		public class AssemblyCacheInstallReferenceEnum
		{
			public AssemblyCacheInstallReferenceEnum(String assemblyName)
			{
				IAssemblyName fusionName = null;

				int hr = Utils.CreateAssemblyNameObject(
							out fusionName,
							assemblyName,
							CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME,
							IntPtr.Zero);

				if (hr >= 0)
				{
					hr = Utils.CreateInstallReferenceEnum(out refEnum, fusionName, 0, IntPtr.Zero);
				}

				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}
			}

			public InstallReference GetNextReference()
			{
				IInstallReferenceItem item = null;
				int hr = refEnum.GetNextInstallReferenceItem(out item, 0, IntPtr.Zero);
				if ((uint)hr == 0x80070103)
				{   // ERROR_NO_MORE_ITEMS
					return null;
				}

				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}

				IntPtr refData;
				InstallReference instRef = new InstallReference(Guid.Empty, String.Empty, String.Empty);

				hr = item.GetReference(out refData, 0, IntPtr.Zero);
				if (hr < 0)
				{
					Marshal.ThrowExceptionForHR(hr);
				}

				Marshal.PtrToStructure(refData, instRef);
				return instRef;
			}

			private IInstallReferenceEnum refEnum;
		}

		internal class Utils
		{
			[DllImport("fusion.dll")]
			internal static extern int CreateAssemblyEnum(
					out IAssemblyEnum ppEnum,
					IntPtr pUnkReserved,
					IAssemblyName pName,
					AssemblyCacheFlags flags,
					IntPtr pvReserved);

			[DllImport("fusion.dll")]
			internal static extern int CreateAssemblyNameObject(
					out IAssemblyName ppAssemblyNameObj,
					[MarshalAs(UnmanagedType.LPWStr)]
				String szAssemblyName,
					CreateAssemblyNameObjectFlags flags,
					IntPtr pvReserved);

			[DllImport("fusion.dll")]
			internal static extern int CreateAssemblyCache(
					out IAssemblyCache ppAsmCache,
					int reserved);

			[DllImport("fusion.dll")]
			internal static extern int CreateInstallReferenceEnum(
					out IInstallReferenceEnum ppRefEnum,
					IAssemblyName pName,
					int dwFlags,
					IntPtr pvReserved);
		}
	}
	public class Library
	{
		public static Map Split(Map y, Map x)
		{
			return x.Split(y);
			//return y.Split(x);
		}
		//public static Map Split(Map y,Map x)
		//{
		//    List<Map> result = new List<Map>();
		//    List<Map> sub=new List<Map>();
		//    foreach(var m in x.Array)
		//    {
		//        if (m.Equals(y))
		//        {
		//            result.Add(new ListMap(sub));
		//            sub = new List<Map>();
		//        }
		//        else
		//        {
		//            sub.Add(m);
		//        }
		//    }
		//    result.Add(new ListMap(sub));
		//    return new ListMap(result);
		//}
		//public static bool StringContains(Map b,Map a)
		//{
		//    for (int i = 0; i < a.ArrayCount; i++)
		//    {
		//        bool match = true;
		//        for (int y = 0; y < b.ArrayCount; y++)
		//        {
		//            int index = i + y+1;
		//            if (index > a.ArrayCount || !a[index].Equals(b[y]))
		//            {
		//                match = false;
		//                break;
		//            }
		//        }
		//        if (match)
		//        {
		//            return true;
		//        }
		//    }
		//    return false;
		//    //return b.Contains(a);
		//}
		public static bool StringContains(string a, string b)
		{
			return b.Contains(a);
		}
		// TODO: allow fractions and negative numbers as exponents
		public static Map Raise(Number a, Number b)
		{
			Integer x=b.GetInteger();
			if (x == null)
			{
				throw new Exception("Exponent is not an integer.");
			}
            int exponent=a.GetInt32();
            if(exponent<0)
            {
                throw new Exception("Exponent must not be negativ.");
            }
			// TODO: optimize
			return new Rational(
				new LargeInteger(IntX.Pow(x.Numerator.GetLargeInteger().GetBigInteger(),(uint)exponent)),
				new LargeInteger(IntX.Pow(x.Denominator.GetLargeInteger().GetBigInteger(),(uint)exponent))
			);
		}
		public static int Compare(Number a, Number b)
		{
			return a.CompareTo(b);
		}
		public static bool LessOrEqual(Number a, Number b)
		{
			return a.CompareTo(b)<=0;
		}
		public static bool GreaterOrEqual(Number a, Number b)
		{
			return a.CompareTo(b)>=0;
		}
		public static bool GreaterEqual(Number a, Number b)
		{
			return a.Expand(b).CompareTo(b.Expand(a))>=0;
		}
		public static bool LessEqual(Number a, Number b)
		{
			return LessOrEqual(a, b);
		}
		// TODO: implement modulo for rationals
		public static Number Modulo(Number a, Number b)
		{
			// TODO: fix this
			return new Integer32(a.GetInt32() % b.GetInt32());
		}

		public static Number Multiply(Number a, Number b)
		{
			return a.Multiply(b);
		}
		public static Number Add(Number a, Number b)
		{
			return a.Add(b);
		}
		public static Number Subtract(Number a, Number b)
		{
			return a.Subtract(b);
		}

		public static Number Divide(Number a, Number b)
			{
			// TODO: fix this
			if (Interpreter.simulate)
			{
				return Number.Zero;
			}
			return a.Divide(b);
		}
		public static bool Less(Number a, Number b)
		{
			return a.CompareTo(b)<0;
		}
		public static bool Greater(Number a, Number b)
		{
			return a.CompareTo(b)>0;
		}
		// TODO: bugfix, cannot replace at end
		public static Map Replace(Map array, Map oldValue, Map newValue)
		{
			List<Map> list = new List<Map>();
			for (int i = 1; i <= array.ArrayCount; i++)
			{
				int k = 1;
				for (; i + k <= array.ArrayCount && array[i + k - 1].Equals(oldValue[k]) && k <= oldValue.Count; k++)
				{
				}
				if (k == oldValue.ArrayCount + 1)
				{
					list.AddRange(newValue.Array);
					i += k - 2;
				}
				else
				{
					list.Add(array[i]);
				}
			}
			return new ListMap(list);
		}
		public static Map Count(Map m)
		{
			return m.Count;
		}
		public static Map Length(Map m)
		{
			return m.ArrayCount;
		}
		// remove?
		public static Map Fold(Map func, Map value,Map start)
		{
			int count = value.ArrayCount;
			if (count == 0)
			{
				return EmptyMap.Empty;
			}
			else if (count == 1)
			{
				return value;
			}
			else
			{
				Map result = start;
				//Map result = value[1];
				for (int i = 1; i <= count; i++)
				{
					// TODO: think about argument order
					result = func.Call(value[i]).Call(result);
					//result = func.Call(result).Call(value[i]);
					//result = func.Call(value[i].Copy()).Call(result);
				
				
				}
				return result;
			}
		}
		public static Map While(Map func,Map condition)
		{

			ListMap map = new ListMap();
			while (condition.Call(EmptyMap.Empty).GetInt32() == 1)
			{
				map.Append(func.Call(EmptyMap.Empty));
				if (Interpreter.simulate)
				{
					break;
				}
			}
			return map;
		}
		public static Map ToUpper(string s)
		{
			return s.ToUpper();
		}
		public static Map ToLower(string s)
		{
			return s.ToLower();
		}
		public static Map Trim(string s, string c)
		{
			return s.Trim(c.ToCharArray());
		}
		//public static Map XmlToMap(string s)
		//{
		//    if (s == "")
		//    {
		//        return new DictionaryMap();
		//    }
		//    XmlDocument doc = new XmlDocument();
		//    doc.LoadXml(s);
		//    DictionaryMap map = new DictionaryMap();
		//    map[doc.DocumentElement.Name] = XmlToMap(doc.DocumentElement);
		//    return map;
		//}
		//private static Map XmlToMap(XmlNode node)
		//{
		//    if (node.Attributes == null && (node.ChildNodes.Count == 0 || (node.ChildNodes.Count == 1 && node.ChildNodes[0] is XmlText)))
		//    {
		//        return node.InnerText;
		//    }
		//    Map current = new DictionaryMap();
		//    if (node.Attributes != null)
		//    {
		//        foreach (XmlAttribute attribute in node.Attributes)
		//        {
		//            current[attribute.Name] = attribute.Value;
		//        }
		//    }
		//    Dictionary<string, List<XmlNode>> grouped = new Dictionary<string, List<XmlNode>>();
		//    List<XmlNode> list = new List<XmlNode>();
		//    foreach (XmlNode n in node.ChildNodes)
		//    {
		//        if (!grouped.ContainsKey(n.Name))
		//        {
		//            grouped[n.Name] = new List<XmlNode>();
		//        }
		//        grouped[n.Name].Add(n);
		//    }
		//    foreach (var x in grouped)
		//        //foreach (var x in list.GroupBy(a => a.Name))
		//    {
		//        ListMap l = new ListMap();
		//        foreach (var y in x.Value)
		//        {
		//            if (y is XmlText)
		//            {
		//                return y.InnerText;
		//            }
		//            l.Append(XmlToMap(y));
		//        }
		//        current[x.Key] = l;
		//    }
		//    return current;
		//}
		//private static Map XmlToMap(XmlNode node)
		//{
		//    if (node.Attributes == null && (node.ChildNodes.Count == 0 || (node.ChildNodes.Count == 1 && node.ChildNodes[0] is XmlText)))
		//    {
		//        return node.InnerText;
		//    }
		//    Map current = new DictionaryMap();
		//    if (node.Attributes != null)
		//    {
		//        foreach (XmlAttribute attribute in node.Attributes)
		//        {
		//            current[attribute.Name] = attribute.Value;
		//        }
		//    }
		//    Dictionary<string, XmlNode> grouped = new Dictionary<string, XmlNode>();
		//    List<XmlNode> list = new List<XmlNode>();
		//    foreach (XmlNode n in node.ChildNodes)
		//    {
		//        list.Add(n);
		//    }
		//    foreach (var x in list.GroupBy(a => a.Name))
		//    {
		//        ListMap l = new ListMap();
		//        foreach (var y in x)
		//        {
		//            if (y is XmlText)
		//            {
		//                return y.InnerText;
		//            }
		//            l.Append(XmlToMap(y));
		//        }
		//        current[x.Key] = l;
		//    }
		//    return current;
		//}
		public static Map ToMap(System.Collections.Specialized.NameValueCollection m)
		{
			DictionaryMap map = new DictionaryMap();
			foreach (string s in m.Keys)
			{
				map[s] = m[s];
			}
			return map;
		}
		public static string ToString(Map m)
		{
			if (m.GetNumber() == null)
			{
			}
			return m.ToString();
		}
		//public static Map StoredProcedure(string connectionString, string storedProcedure, Map parameters)
		//{
		//    using (OleDbConnection connection = new OleDbConnection(connectionString))
		//    {
		//        connection.Open();
		//        OleDbCommand command = new OleDbCommand(storedProcedure, connection);
		//        command.CommandType = System.Data.CommandType.StoredProcedure;
		//        OleDbCommandBuilder.DeriveParameters(command);
		//        int count = 0;
		//        foreach (Map parameter in parameters.Array)
		//        {
		//            Type type;
		//            var t = command.Parameters[count + 1].DbType;
		//            switch (t)
		//            {
		//                case System.Data.DbType.AnsiString:
		//                case System.Data.DbType.AnsiStringFixedLength:
		//                case System.Data.DbType.Binary:
		//                case System.Data.DbType.Boolean:
		//                case System.Data.DbType.Byte:
		//                case System.Data.DbType.Currency:
		//                case System.Data.DbType.Date:
		//                case System.Data.DbType.DateTime:
		//                case System.Data.DbType.DateTime2:
		//                case System.Data.DbType.DateTimeOffset:
		//                case System.Data.DbType.Decimal:
		//                case System.Data.DbType.Double:
		//                case System.Data.DbType.Guid:
		//                case System.Data.DbType.Int16:
		//                case System.Data.DbType.Int32:
		//                case System.Data.DbType.Int64:
		//                case System.Data.DbType.Object:
		//                case System.Data.DbType.SByte:
		//                case System.Data.DbType.Single:
		//                case System.Data.DbType.StringFixedLength:
		//                case System.Data.DbType.Time:
		//                case System.Data.DbType.UInt16:
		//                case System.Data.DbType.UInt32:
		//                case System.Data.DbType.UInt64:
		//                case System.Data.DbType.VarNumeric:
		//                case System.Data.DbType.Xml:
		//                    throw new Exception("Type not supported: " + t);
		//                case System.Data.DbType.String:
		//                    type = typeof(string);
		//                    break;
		//                default:
		//                    type = typeof(int);
		//                    break;
		//            }
		//            command.Parameters[count + 1].Value = Transform.ToDotNet(parameter, type);
		//            count++;

		//        }
		//        Map result = new DictionaryMap();
		//        OleDbDataReader reader = command.ExecuteReader();
		//        while (reader.Read())
		//        {
		//            Map entry = new DictionaryMap();
		//            for (int i = 0; i < reader.FieldCount; i++)
		//            {
		//                entry[reader.GetName(i)] = Transform.ToMeta(reader[i]);
		//            }
		//            result.Append(entry);
		//        }
		//        return result;
		//    }
		//}
		public static ObjectMap Cast(object obj, Type type)
		{
			return new ObjectMap(obj, type);
		}
		public static bool IsString(Map m)
		{
			return m.IsString;
		}
		public static bool IsArray(Map m)
		{
			return m.ArrayCount == m.Count;
		}
		public static object Subclass(Type type, Map functions)
		{
			//const string assemblyPath = @"c:\meta\bin\Debug\";
			TypeBuilder tb;

			AssemblyBuilder ab;

			AppDomain cd = System.Threading.Thread.GetDomain();
			AssemblyName an = new AssemblyName();
			an.Name = "HelloClass";
			ab = cd.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
			//ab = cd.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run, assemblyPath);
			//ab = cd.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, assemblyPath);
			ModuleBuilder mb = ab.DefineDynamicModule("HelloModule", "HelloModule.dll", true);
			tb = mb.DefineType("Hello", TypeAttributes.Class | TypeAttributes.Public, type);

			int count = 0;
			foreach (KeyValuePair<Map, Map> entry in functions)
			{
				string name = entry.Key.GetString();

				MethodMember methodMember = (MethodMember)ObjectMap.allCache.GetMembers(type)[entry.Key.GetString()];

				MethodInfo method = (MethodInfo)methodMember.method;// type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				//MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				//MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				//MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

				List<Type> parameters = new List<Type>();
				foreach (ParameterInfo parameter in method.GetParameters())
				{
					parameters.Add(parameter.ParameterType);
				}
				//MethodAttributes attributes;
				//if(method.IsPrivate)
				//{
				//    attributes=MethodAttributes.Private;
				//}
				//else
				//{
				//    attributes=MethodAttributes.Public;
				//}


				const MethodAttributes MethodAttributesToEraseInOveride = MethodAttributes.Abstract | MethodAttributes.ReservedMask;



				MethodAttributes finalAttrs = (method.Attributes & ~MethodAttributesToEraseInOveride);// | extraAttrs;
				//MethodAttributes finalAttrs = (method.Attributes & ~MethodAttributesToEraseInOveride) | extraAttrs;
				MethodBuilder methodBuilder = tb.DefineMethod(method.Name, finalAttrs, method.ReturnType,
					parameters.ToArray());
				//CodeGen ret = new CodeGen(this, mb, mb.GetILGenerator(), baseMethod.GetParameters());
				//ret.methodToOverride = baseMethod;
				//return ret;



				//MethodBuilder methodBuilder = tb.DefineMethod("Test", method.Attributes, method.ReturnType, parameters.ToArray());
				//MethodBuilder methodBuilder = tb.DefineMethod(name, method.Attributes, method.ReturnType, parameters.ToArray());
				//MethodBuilder methodBuilder = tb.DefineMethod(name, method.Attributes, method.ReturnType, parameters.ToArray());
				//ILGenerator il = methodBuilder.GetILGenerator();


				//MethodInfo invoke = delegateType.GetMethod("Invoke");
				ParameterInfo[] p = method.GetParameters();
				Emitter il = new Emitter(methodBuilder.GetILGenerator());

				LocalBuilder current = il.DeclareLocal(typeof(Map));
				il.LoadArgument(0);
				//il.LoadField(
				FieldBuilder field = tb.DefineField("field" + count, typeof(Map), FieldAttributes.Private);
				il.LoadField(field);
				il.StoreLocal(current);

				if (p.Length == 0)
				{
					il.LoadLocal(current);
					il.LoadField(typeof(Map).GetField("Empty"));// (i + 1);
					//Transform.GetMetaConversion(p[i].ParameterType, il);
					il.Call(typeof(Map), "Call");
					il.StoreLocal(current);
				}
				else
				{
					for (int i = 0; i < p.Length; i++)
					{
						il.LoadLocal(current);
						il.LoadArgument(i + 1);
						Transform.GetMetaConversion(p[i].ParameterType, il);
						il.Call(typeof(Map), "Call");
						il.StoreLocal(current);
					}
				}

				if (method.ReturnType == typeof(void))
				{
					il.Return();
				}
				else
				{
					il.LoadLocal(current);
					Transform.GetDotNetConversion(method.ReturnType, il);
					il.Return();
				}
				//il.LoadConstant("success!");
				//il.Return();




				//tb.DefineMethodOverride(methodBuilder, method);

				//return (Delegate)il.GetDelegate(code);

				//foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) ;


				//il = meth.GetILGenerator();
				//this.dynamicMethod = new DynamicMethod("Optimized", invoke.ReturnType, parameters.ToArray(), typeof(Map).Module);



				//Delegate del = Delegate.CreateDelegate(type, instance, myType.GetMethod("HelloWorld"));
				//return del;

				tb.DefineMethodOverride(methodBuilder, method);
				count++;
			}
			Type myType = tb.CreateType();
			ab.Save("MetaDynamic.dll");
			object result = myType.GetConstructor(new Type[] { }).Invoke(new object[] { });
			int index = 0;
			foreach (KeyValuePair<Map, Map> entry in functions)
			{
				FieldInfo field = result.GetType().GetField("field" + index, BindingFlags.Instance | BindingFlags.NonPublic);
				field.SetValue(result, entry.Value);
				index++;
			}
			return result;
		}


		//public static object Subclass(Type type, Map functions)
		//{
		//    const string assemblyPath = @"c:\meta\bin\Debug\";
		//    TypeBuilder tb;

		//    AssemblyBuilder ab;

		//    AppDomain cd = System.Threading.Thread.GetDomain();
		//    AssemblyName an = new AssemblyName();
		//    an.Name = "HelloClass";
		//    ab = cd.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, assemblyPath);
		//    ModuleBuilder mb = ab.DefineDynamicModule("HelloModule", "HelloModule.dll", true);
		//    tb = mb.DefineType("Hello", TypeAttributes.Class | TypeAttributes.Public,type);


		//    foreach (KeyValuePair<Map, Map> entry in functions)
		//    {
		//        string name = entry.Key.GetString();
		//        MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		//        List<Type> parameters = new List<Type>();
		//        foreach (ParameterInfo parameter in method.GetParameters())
		//        {
		//            parameters.Add(parameter.ParameterType);
		//        }
		//        //MethodAttributes attributes;
		//        //if(method.IsPrivate)
		//        //{
		//        //    attributes=MethodAttributes.Private;
		//        //}
		//        //else
		//        //{
		//        //    attributes=MethodAttributes.Public;
		//        //}
		//        MethodBuilder methodBuilder = tb.DefineMethod(name, method.Attributes, method.ReturnType, parameters.ToArray());
		//        //ILGenerator il = methodBuilder.GetILGenerator();


		//        //MethodInfo invoke = delegateType.GetMethod("Invoke");
		//        ParameterInfo[] p = method.GetParameters();
		//        Emitter il = new Emitter(methodBuilder.GetILGenerator());

		//        LocalBuilder current = il.DeclareLocal(typeof(Map));
		//        il.LoadArgument(0);
		//        il.StoreLocal(current);

		//        for (int i = 0; i < p.Length; i++)
		//        {
		//            il.LoadLocal(current);
		//            il.LoadArgument(i + 1);
		//            Transform.GetMetaConversion(p[i].ParameterType, il);
		//            il.Call(typeof(Map), "Call");
		//            il.StoreLocal(current);
		//        }

		//        if (method.ReturnType == typeof(void))
		//        {
		//            il.Return();
		//        }
		//        else
		//        {
		//            il.LoadLocal(current);
		//            Transform.GetDotNetConversion(method.ReturnType, il);
		//            il.Return();
		//        }
		//        //return (Delegate)il.GetDelegate(code);

		//        //foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) ;


		//        //il = meth.GetILGenerator();
		//        //this.dynamicMethod = new DynamicMethod("Optimized", invoke.ReturnType, parameters.ToArray(), typeof(Map).Module);



		//        //Delegate del = Delegate.CreateDelegate(type, instance, myType.GetMethod("HelloWorld"));
		//        //return del;


		//    }
		//    Type myType = tb.CreateType();
		//    ab.Save("MetaDynamic.dll");
		//    return myType.GetConstructor(new Type[] { }).Invoke(new object[] { });
		//}
		public static bool Contains(Map map, Map key)
		{
			return map.ContainsKey(key);
		}
		public static bool ListContains(Map list, Map key)
		{
			foreach (Map value in list.Array)
			{
				if (key.Equals(value))
				{
					return true;
				}
			}
			return false;
		}
		// number classes could be replaced with generic class
		public class Float
		{
			public static float Add(float a, float b)
			{
				return a + b;
			}
			public static float Subtract(float a, float b)
			{
				return a - b;
			}
			public static float Multiply(float a, float b)
			{
				return a * b;
			}
			public static float Divide(float a, float b)
			{
				return a / b;
			}
			public static bool Equal(float a, float b)
			{
				return a == b;
			}
			public static bool GreaterEqual(float a, float b)
			{
				return a >= b;
			}
			public static bool Greater(float a, float b)
			{
				return a > b;
			}
			public static bool LessEqual(float a, float b)
			{
				return a <= b;
			}
			public static bool Less(float a, float b)
			{
				return a < b;
			}
		}
		public class Double
		{
			//public static double Power(double exponent,double b)
			//{
			//    Math.Pow(
			//}
			public static double Add(double a, double b)
			{
				return a + b;
			}
			public static double Subtract(double a, double b)
			{
				return a - b;
			}
			public static double Multiply(double a, double b)
			{
				return a * b;
			}
			public static double Divide(double a, double b)
			{
				return a / b;
			}
			public static bool Equal(double a, double b)
			{
				return a == b;
			}
			public static bool GreaterEqual(double a, double b)
			{
				return a >= b;
			}
			public static bool Greater(double a, double b)
			{
				return a > b;
			}
			public static bool LessEqual(double a, double b)
			{
				return a <= b;
			}
			public static bool Less(double a, double b)
			{
				return a < b;
			}
		}
		public class Int32
		{
			public static int Add(int a, int b)
			{
				return a + b;
			}
			public static int Subtract(int a, int b)
			{
				return a - b;
			}
			public static int Multiply(int a, int b)
			{
				return a * b;
			}
			public static int Divide(int a, int b)
			{
				return a / b;
			}

			public static int AddUnchecked(int a, int b)
			{
				unchecked
				{
					return a + b;
				}
			}
			public static int SubtractUnchecked(int a, int b)
			{
				unchecked
				{
					return a - b;
				}
			}
			public static int MultiplyUnchecked(int a, int b)
			{
				unchecked
				{
					return a * b;
				}
			}

			public static bool Equal(int a, int b)
			{
				return a == b;
			}
			public static bool GreaterEqual(int a, int b)
			{
				return a >= b;
			}
			public static bool Greater(int a, int b)
			{
				return a > b;
			}
			public static bool LessEqual(int a, int b)
			{
				return a <= b;
			}
			public static bool Less(int a, int b)
			{
				return a < b;
			}
		}
		public class Int64
		{
			public static long Add(long a, long b)
			{
				return a + b;
			}
			public static long Subtract(long a, long b)
			{
				return a - b;
			}
			public static long Multiply(long a, long b)
			{
				return a * b;
			}
			public static long Divide(long a, long b)
			{
				return a / b;
			}
			public static long AddUnchecked(long a, long b)
			{
				unchecked
				{
					return a + b;
				}
			}
			public static long SubtractUnchecked(long a, long b)
			{
				unchecked
				{
					return a - b;
				}
			}
			public static long MultiplyUnchecked(long a, long b)
			{
				unchecked
				{
					return a * b;
				}
			}
			public static bool Equal(long a, long b)
			{
				return a == b;
			}
			public static bool GreaterEqual(long a, long b)
			{
				return a >= b;
			}
			public static bool Greater(long a, long b)
			{
				return a > b;
			}
			public static bool LessEqual(long a, long b)
			{
				return a <= b;
			}
			public static bool Less(long a, long b)
			{
				return a < b;
			}
		}
		public static Map Slice(Map array, int start, int end)
		{
			return new ListMap(new List<Map>(array.Array).GetRange(start - 1, Math.Max(end - start + 1, 0)));
		}
		public static Map Select(Map array, Map function)
		{
			foreach (Map m in array.Array)
			{
				if (Convert.ToBoolean(function.Call(m).GetNumber().GetInt32()))
				{
					return m;
				}
			}
			throw new Exception("Predicate was false for all items in the array.");
		}
		public static Map Rest(Map m)
		{
			return new DictionaryMap(new List<Map>(m.Array).GetRange(1, m.ArrayCount - 1));
		}
		public static Number Ceiling(Number n)
		{
			return n.Numerator.Divide(n.Denominator).Add(Integer.One);
			//n.GetLargeInteger
			//// TODO: fix this
			//return new LargeInteger((n.GetRealInt64() + 1).ToString());
		}
		public static Number Floor(Number n)
		{
			return n.Numerator.Divide(n.Denominator).Add(Integer.One);
			//return new Rational(n.GetRealInt64());
		}
		public static string WriteLine(string s)
		{
			Console.WriteLine(s);
			return s;
		}
		private static Random random = new Random();
		public static int Random(int lower, int upper)
		{
			return lower + Convert.ToInt32((random.NextDouble() * (upper - lower)));
		}
		public static string Trim(string text)
		{
			return text.Trim();
		}
		public static Map Modify(Map map, Map func)
		{
			Map result = new DictionaryMap();
			foreach (KeyValuePair<Map, Map> entry in map)
			{
				result[entry.Key] = func.Call(entry.Key).Call(entry.Value);
			}
			return result;
		}
		public static Map StringToNumber(Map map)
		{
			return Convert.ToInt32(map.GetString());
		}
		public static Map Foreach(Map map, Map func)
		{
			List<Map> result = new List<Map>();
			foreach (KeyValuePair<Map, Map> entry in map)
			{
				result.Add(func.Call(entry.Key).Call(entry.Value));
			}
			return new DictionaryMap(result);
		}
		public static Map Switch(Map map, Map cases)
		{
			foreach (KeyValuePair<Map, Map> entry in cases)
			{
				if (Convert.ToBoolean(entry.Key.Call(map).GetNumber().GetInt32()))
				{
					return entry.Value.Call(map);
				}
			}
			return new DictionaryMap();
		}
		//public static int CompareNumber(Number a, Number b)
		//{
		//    return a.CompareTo(b);
		//}
		public static Map OrderBy(Map func,Map array)
		{
			List<Map> result = new List<Map>(array.Array);
			result.Sort(delegate(Map a, Map b)
			{
				return func.Call(a).GetNumber().CompareTo(func.Call(b).GetNumber());
				//return (int)Transform.ToDotNet(function.Call(a).Call(b), typeof(int));
			});
			return new DictionaryMap(result);
		}
		public static Map Order(Map array)
		{
			List<Map> result = new List<Map>(array.Array);
			result.Sort(delegate(Map a, Map b)
			{
				return a.GetNumber().CompareTo(b.GetNumber());
				//return (int)Transform.ToDotNet(function.Call(a).Call(b), typeof(int));
			});
			return new DictionaryMap(result);
		}
		public static Map Sort(Map array, Map function)
		{
			List<Map> result = new List<Map>(array.Array);
			result.Sort(delegate(Map a, Map b)
			{
				return (int)Transform.ToDotNet(function.Call(a).Call(b), typeof(int));
			});
			return new DictionaryMap(result);
		}
		public static bool Equal(object a, object b)
		{
			return a.Equals(b);
		}
		public static Map Filter(Map array, Map condition)
		{
			List<Map> result = new List<Map>();
			foreach (Map m in array.Array)
			{
				if (Convert.ToBoolean(condition.Call(m).GetNumber().GetInt32()))
				{
					result.Add(m);
				}
			}
			return new DictionaryMap(result);
		}
		public static Map IfElse(bool condition, Map then, Map els)
		{
			if (condition)
			{
				return then.Call(EmptyMap.Empty);
			}
			else
			{
				return els.Call(EmptyMap.Empty);
			}
		}
		public static Map Sum(Map func, Map arg)
		{
			IEnumerator<Map> enumerator = arg.Array.GetEnumerator();
			if (enumerator.MoveNext())
			{
				Map result = enumerator.Current.Copy();
				while (enumerator.MoveNext())
				{
					result = func.Call(result).Call(enumerator.Current);
				}
				return result;
			}
			else
			{
				return EmptyMap.Empty;
			}
		}
		public static Map GetSingle(Map m)
		{
			return new ObjectMap(m.GetNumber().GetSingle());
		}
		public static Map GetInt16(Map m)
		{
			return new ObjectMap(m.GetNumber().GetInt16());
		}
		public static Map GetInt32(Map m)
		{
			return new ObjectMap(m.GetNumber().GetInt32());
		}
		//public static Map GetInt64(Map m)
		//{
		//    return new ObjectMap(m.GetNumber().GetInt64());
		//}
		public static Map JoinAll(Map arrays)
		{
			List<Map> result = new List<Map>();
			foreach (Map array in arrays.Array)
			{
				result.AddRange(array.Array);
			}
			return new ListMap(result);
		}
		public static Map If(bool condition, Map then,Map els)
		{
			if (condition)
			{
				return then.Call(EmptyMap.Empty);
			}
			else
			{
				return els.Call(EmptyMap.Empty);
			}
			//return Map.Empty;
		}
		public static Map Keys(Map m)
		{
			return new DictionaryMap(m.Keys);
		}
		public static Map Apply(Map func,Map array)
		{
			//if (array.ArrayCount > 100)
			//{
			//    List<Thread> workers = new List<Thread>();
			//    List<Map> r = new List<Map>();
			//    List<Map> args = new List<Map>(array.Array);

			//    int processorCount = 2;
			//    int step = args.Count / processorCount + 1;


			//    List<Map>[] arg = new List<Map>[processorCount];

			//    List<IAsyncResult> async = new List<IAsyncResult>();
			//    for (int i = 0; i < processorCount; i++)
			//    {
			//        if (i == processorCount - 1)
			//        {
			//            if (Map.arguments == null)
			//            {
			//                Map.arguments = new Stack<Map>();
			//            }
			//            //Interpreter interpreter = Interpreter.Current;
			//            List<Map> a = (List<Map>)args.GetRange(i * step, Math.Min(step, (args.Count - i * step)));
			//            List<Map> result = new List<Map>();
			//            foreach (Map map in a)
			//            {
			//                result.Add(func.Call(map));
			//            }
			//            lock (r)
			//            {
			//                r.AddRange(result);
			//            }
			//        }
			//        else
			//        {
			//            async.Add(new ParameterizedThreadStart(delegate(object p)
			//            {
			//                if (Map.arguments == null)
			//                {
			//                    Map.arguments = new Stack<Map>();
			//                }
			//                //Interpreter interpreter = Interpreter.Current;
			//                List<Map> a = (List<Map>)p;
			//                List<Map> result = new List<Map>();
			//                foreach (Map map in a)
			//                {
			//                    result.Add(func.Call(map));
			//                }
			//                lock (r)
			//                {
			//                    r.AddRange(result);
			//                }
			//            }
			//            ).BeginInvoke(args.GetRange(i * step, Math.Min(step, (args.Count - i * step))), null, null));
			//        }
			//    }
			//    foreach (IAsyncResult a in async)
			//    {
			//        a.AsyncWaitHandle.WaitOne();
			//    }
			//    return new ListMap(r);
			//}
			//else
			{
				List<Map> result = new List<Map>();
				//Interpreter interpreter = Interpreter.Current;
				foreach (Map map in array.Array)
				{
					result.Add(func.Call(map));
					if (Interpreter.simulate)
					{
						break;
					}
				}
				return new ListMap(result);
			}
		}
		//public static Map Apply(Map array, Map func)
		//{
		//    if (array.ArrayCount > 100)
		//    {
		//        List<Thread> workers = new List<Thread>();
		//        List<Map> r = new List<Map>();
		//        List<Map> args = new List<Map>(array.Array);

		//        int processorCount = 2;//Environment.ProcessorCount
		//        int step = args.Count / processorCount + 1;

		//        List<Map>[] arg = new List<Map>[processorCount];

		//        for (int i = 0; i < processorCount; i++)
		//        {
		//            Thread thread = new Thread(new ParameterizedThreadStart(delegate(object p)
		//            {
						//if (Map.arguments == null)
						//{
						//    Map.arguments = new Stack<Map>();
						//}
		//                List<Map> a = (List<Map>)p;
		//                List<Map> result = new List<Map>();
		//                foreach (Map map in a)
		//                {
		//                    result.Add(func.Call(map));
		//                }
		//                lock (r)
		//                {
		//                    r.AddRange(result);
		//                }
		//            }
		//            ));
		//            workers.Add(thread);

		//            arg[i] = args.GetRange(i * step, Math.Min(step, (args.Count - i * step)));
		//        }
		//        for (int i = 0; i < processorCount; i++)
		//        {
		//            workers[i].Start(arg[i]);
		//        }
		//        foreach (Thread t in workers)
		//        {
		//            t.Join();
		//        }
		//        return new ListMap(r);
		//    }
		//    else
		//    {
		//        List<Map> result = new List<Map>();
		//        foreach (Map map in array.Array)
		//        {
		//            result.Add(func.Call(map));
		//        }
		//        return new ListMap(result);
		//    }
		//}
		//public static Map Apply(Map array, Map func)
		//{
		//    List<Map> result = new List<Map>();
		//    foreach (Map map in array.Array)
		//    {
		//        result.Add(func.Call(map));
		//    }
		//    return new DictionaryMap(result);
		//}
		public static Map Append(Map array, Map item)
		{
			Map result = new ListMap(new List<Map>(array.Array));
			result.Append(item);
			return result;
		}
		public static Map EnumerableToArray(Map map)
		{
			List<Map> result = new List<Map>();
			foreach (object entry in (System.Collections.IEnumerable)((ObjectMap)map).Object)
			{
				result.Add(Transform.ToMeta(entry));
			}
			return new DictionaryMap(result);
		}
		public static Map Reverse(Map arg)
		{
			List<Map> list = new List<Map>(arg.Array);
			list.Reverse();
			return new DictionaryMap(list);
		}
		public static Map Try(Map tryFunction, Map catchFunction)//,Map finallyFunction)
		{
			try
			{
				return tryFunction.Call(EmptyMap.Empty);
			}
			catch (Exception e)
			{
				return catchFunction.Call(new ObjectMap(e));
			}
			//finally
			//{
			//    finallyFunction.Call(EmptyMap.Empty);
			//}
		}
		public static Map Using(Map tryFunction,IDisposable disposable)
		{
			using (disposable)
			{
				return tryFunction.Call(new ObjectMap(disposable));
			}
		}
		public static Map With(Map o, Map values)
		{
			if (Interpreter.simulate)
			{
				return o;
			}
			try
			{
				object obj = ((ObjectMap)o).Object;
				Type type = obj.GetType();
				foreach (KeyValuePair<Map, Map> entry in values)
				{
					Map value = entry.Value;
					//if (entry.Key is ObjectMap)
					//{
					//    System.Windows.DependencyProperty key = (System.Windows.DependencyProperty)((ObjectMap)entry.Key).Object;
					//    type.GetMethod("SetValue", new Type[] { typeof(System.Windows.DependencyProperty), typeof(Object) }).Invoke(obj, new object[] { key, Transform.ToDotNet(value, key.PropertyType) });
					//}
					//else
					//{
					MemberInfo[] members = type.GetMember(entry.Key.GetString());
					if (members.Length != 0)
					{
						MemberInfo member = members[0];
						if (member is FieldInfo)
						{
							FieldInfo field = (FieldInfo)member;
							field.SetValue(obj, Transform.ToDotNet(value, field.FieldType));
						}
						else if (member is PropertyInfo)
						{
							PropertyInfo property = (PropertyInfo)member;
							object converted = Transform.ToDotNet(value, property.PropertyType);
							property.SetValue(obj, converted, null);
						}
						else if (member is EventInfo)
						{
							EventInfo eventInfo = (EventInfo)member;
							new Method(eventInfo.GetAddMethod(), obj, type, eventInfo).Call(value);
						}
						else
						{
							throw new Exception("unknown member type");
						}
					}
					else
					{
						o[entry.Key] = entry.Value;
					}
					//}
				}
				return o;
			}
			catch (Exception e)
			{
				With(o, values);
				throw;
			}
		}
		public static Map MergeAll(Map array)
		{
			Map result = new DictionaryMap();
			foreach (Map map in array.Array)
			{
				if (map is DotNetMap)
				{
					Console.WriteLine("hello");
				}
				foreach (KeyValuePair<Map, Map> pair in map)
				{
					result[pair.Key] = pair.Value;
				}
			}
			return result;
		}
		public static Map Merge(Map arg, Map map)
		{
			DictionaryMap m = new DictionaryMap();
			foreach (KeyValuePair<Map, Map> pair in arg)
			{
				m[pair.Key] = pair.Value;
			}
			foreach (KeyValuePair<Map, Map> pair in map)
			{
				m[pair.Key] = pair.Value;
			}
			return m;
		}
		public static Map Join(Map arg, Map map)
		{
			return arg.Join(map);
		}
		public static Map Range(Number arg)
		{
			Map result = new ListMap();
			for (int i = 1; Library.LessEqual(new Integer32(i), arg); i++)
			{
				result.Append(i);
			}
			return result;
		}
	}

	//public class MetaFileMap : ScopeMap
	//{
	//    private string file;
	//    public MetaFileMap(string file)
	//    {
	//        this.file = file;
	//    }
	//}
	/// <summary>
	/// Represents a directory as a Meta map.
	/// </summary>
	[Serializable]
	public class DirectoryMap : ScopeMap
	{
		public override int Count
		{
			get
			{
				return Cache.Count;
			}
		}
		protected Dictionary<Map, Map> _cache;
		protected virtual Dictionary<Map, Map> Cache
		{
			get
			{
				if (_cache == null)
				{
					_cache = new Dictionary<Map, Map>();
					foreach (string dll in Directory.GetFiles(path, "*.dll"))
					{
						Assembly assembly = null;
						try
						{
							assembly = Assembly.LoadFrom(dll);
						}
						catch (Exception e)
						{
						};
						if (assembly != null)
						{
							_cache[Path.GetFileNameWithoutExtension(dll)] = new AssemblyMap(assembly);
						}
					}
					foreach (string file in Directory.GetFiles(path))
					{
						string name;
						const string meta = ".meta";
						Map map;
						if (file.EndsWith(meta))
						{
							name = Path.GetFileNameWithoutExtension(file);
							map = Parser.Parse(file);
							map.Scope = this;
						}
						else
						{
							name = Path.GetFileName(file);
							map = new FileMap(file);
						}
						_cache[name] = map;
					}
					foreach (string directory in Directory.GetDirectories(path))
					{
						if (!new DirectoryInfo(directory).Name.StartsWith("."))
						{
							_cache[new DirectoryInfo(directory).Name] = new DirectoryMap(directory);
						}
					}
					_cache["gac"] = Gac.gac;
				}
				return _cache;
			}
		}
		public override Map this[Map key]
		{
			get
			{
				if (Cache.ContainsKey(key))
				{
					return Cache[key];
				}
				return null;
			}
			set
			{
				throw new ApplicationException("Cannot set key in directory.");
			}
		}
		private List<Map> keys;
		public override IEnumerable<Map> Keys
		{
			get
			{
				return Cache.Keys;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public readonly string path;
		public DirectoryMap(string path)
		{
			this.path = path;
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override bool ContainsKey(Map key)
		{
			return Cache.ContainsKey(key);
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override Map Copy()
		{
			return CopyMap(this);
		}
	}

	/// <summary>
	/// Represents a file as a Meta map.
	/// </summary>
	[Serializable]
	public class FileMap : ScopeMap
	{
		public override int Count
		{
			get
			{
				return 0;
				//throw new Exception("The method or operation is not implemented.");
			}
		}
		public Stream GetStream()
		{
			return File.Open(path, FileMode.Open);
		}
		public override Map this[Map key]
		{
			get
			{
				return null;
			}
			set
			{
				throw new Exception("Cannot set key in file.");
			}
		}
		public string Path
		{
			get
			{
				return path;
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				yield break;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override bool ContainsKey(Map key)
		{
			return false;
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override Map Copy()
		{
			return this;
		}
		public readonly string path;
		public FileMap(string path)
		{
			this.path = path;
		}
	}
	[Serializable]
	public abstract class ScopeMap : Map
	{
		public override Extent Source
		{
			get
			{
				return source;
			}
			set
			{
				source = value;
			}
		}
		private Extent source;

		private Map scope;
		[Ignore]
		public override Map Scope
		{
			get
			{
				return scope;
			}
			set
			{
				scope = value;
			}
		}

		private Expression expression;
		public override Expression Expression
		{
			get
			{
				return expression;
			}
			set
			{
				expression = value;
			}
		}
	}
	/// <summary>
	/// Base class for all Meta values.
	/// </summary>
	[Serializable]
	public abstract class Map : IEnumerable<KeyValuePair<Map, Map>>, ISerializeEnumerableSpecial
	{
		public static Map Empty = new EmptyMap(null);
		public virtual Map Split(Map x)
		{
			List<Map> result = new List<Map>();
			List<Map> sub = new List<Map>();
			foreach (var m in this.Array)
			{
				if (m.Equals(x))
				{
					result.Add(new ListMap(sub));
					sub = new List<Map>();
				}
				else
				{
					sub.Add(m);
				}
			}
			result.Add(new ListMap(sub));
			return new ListMap(result);
		}
		public virtual Map Join(Map map)
		{
			List<Map> l = new List<Map>(this.Array);
			l.AddRange(map.Array);
			return new ListMap(l);
		}
		public virtual Map Evaluate(ref Map context)
		{
			//if (breakpoint != null)
			//{
			//    if (OnBreakPoint != null)
			//    {
			//        OnBreakPoint(this, context);
			//    }
			//}
			//return EvaluateImplementation(ref context);
			return null;
		}
		public virtual Integer GetInteger()
		{
			Number number = GetNumber();
			if (number != null)
			{
				return number.GetInteger();
			}
			return null;

		}
		public virtual Map GetFromIndex(int i)
		{
			throw new Exception("not implemented");
		}
		public virtual short GetInt16()
		{
			return (short)GetInt32();
		}
		public bool GetBoolean()
		{
			int i = GetInt32();
			if (i == 1)
			{
				return true;
			}
			else if (i == 0)
			{
				return false;
			}
			throw new Exception("Map is not a boolean.");
		}
		public virtual int GetInt32()
		{
			return GetNumber().GetInt32();
		}
		public virtual uint GetUInt32()
		{
			return (uint)GetInt32();
		}
		public virtual Map Copy(Map scope)
		{
			Map copy = Copy();
			copy.Scope = Scope;
			return copy;
		}
		public virtual void CopyInternal(Map map)
		{
			throw new Exception("not implemented");
		}
		public static int GetHashCode(int i)
		{
			return i % int.MaxValue;
		}
		public override int GetHashCode()
		{
			if (GetInteger() != null)
			//if (GetNumber() != null)
			{
				return (int)(GetNumber().Numerator.Modulo(new LargeInteger(Integer32.smallIntMax)).GetInt32());// .GetInt32() % int.MaxValue);
			}
			else
			{
				unchecked
				{
					// TODO: is this correct?
					if (Count == 0)
					{
						return 0;
					}
					int hash = int.MaxValue / Count;
					if (ContainsKey(Map.One))
					{
						hash += this[Map.One].GetHashCode();
					}
					return hash;
				}
			}
		}
		public static Integer32 Zero = new Integer32(0);
		public static Integer32 One = new Integer32(1);
		public static Integer32 Two = new Integer32(1);
		public virtual object GetObject()
		{
			return this;
		}
		public override bool Equals(object obj)
		{
			if (ReferenceEquals(obj, this))
			{
				return true;
			}
			Map map = obj as Map;
			if (map != null && map.Count == Count)
			{
				foreach (Map key in this.Keys)
				{
					Map otherValue = map[key];
					Map thisValue = this[key];
					if (otherValue == null || otherValue.GetHashCode() != thisValue.GetHashCode() || !otherValue.Equals(thisValue))
					{
						return false;
					}
				}
				return true;
			}
			return false;
		}
		public static Map CopyMap(Map map)
		{
			Map copy = new DictionaryMap();
			foreach (Map key in map.Keys)
			{
				copy[key] = map[key];
			}
			copy.Scope = map.Scope;
			return copy;
		}
		public virtual string GetString()
		{
			if (ArrayCount == Count)
			{
				StringBuilder text = new StringBuilder("");
				foreach (Map map in Array)
				{
					Number number = map.GetNumber();
					if (number == null)
					{
						return null;
					}
					else
					{
						if (number.GetInt32() > Char.MinValue && number.GetInt32() < Char.MaxValue)
						{
							text.Append(Convert.ToChar(number.GetInt32()));
						}
						else
						{
							return null;
						}
					}
				}
				return text.ToString();
			}
			return null;
		}
		public abstract int Count
		{
			get;
		}
		public virtual void Append(Map map)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public virtual Type GetClass()
		{
			return null;
		}
		public virtual Map Call(Map argument)
		{
			if (Expression == null)
			{
				Expression a=GetExpression();
				if(a==null)
				{
					if (Interpreter.simulate)
					{
						return EmptyMap.Empty;
					}
					if (this.Source == null)
					{
					}
					throw new MetaException("Tried to call map that is not a function.",this.Source!=null?this.Source.Start:null);
				}
				Expression e =a.Optimize();
				Expression = e.Optimize();
			}
			if (Expression == null)
			{
				if (Interpreter.simulate)
				{
					return new DictionaryMap();
				}
				else
				{
					throw new MetaException("Map is not an expression.", this.Source != null ? this.Source.Start : null);
				}
			}
			Map.arguments.Add(argument);
			//Map.arguments.Push(argument);
			Map result = Expression.Call(argument, this.Scope);
			Map.arguments.RemoveAt(Map.arguments.Count-1);
			//Map.arguments.Pop();
			return result;
		}
		public Map DeepCopy()
		{
			DictionaryMap clone = new DictionaryMap();
			clone.Scope = Scope;
			clone.Source = Source;
			clone.Expression = Expression;
			//clone.Optimized = Optimized;
			foreach (Map key in Keys)
			{
				try
				{
					clone[key] = this[key].Copy();
				}
				catch
				{
					clone[key] = this[key].Copy();
				}
			}
			return clone;
		}
		public abstract Map Copy();

		//[ThreadStatic]
		public static List<Map> arguments = new List<Map>();
		//public static Stack<Map> arguments = new Stack<Map>();
		public override string ToString()
		{
			if (Count == 0)
			{
				return "0";
			}
			else if (IsString)
			{
				return GetString();
			}
			else
			{
				return Meta.Serialization.Serialize(this);
			}
		}
		public static Dictionary<object, Profile> calls = new Dictionary<object, Profile>();
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}
		protected string EscapeString(string s)
		{
			return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
		}
		// TODO: is this necessary?

		public virtual string Serialize(bool key)
		{
			string text;
			if (this.Count == 0)
			{
				text = "0";
			}
			else if (this.IsString)
			{
				if (this.GetString().Contains("abc"))
				{
				}
				// TODO: fix this
				if (key)
				{
					text = this.GetString();
					if (text.IndexOfAny(Parser.lookupStringForbiddenFirst.ToCharArray()) != -1)
					{
						text = '"' + EscapeString(text) + '"';
					}
				}
				else
				{
					text = "\"" + EscapeString(this.GetString()) + "\"";
				}
			}
			else if (this.GetNumber() != null)
			{
				text = this.GetNumber().ToString();
			}
			else
			{
				text = null;
			}
			return text;
		}
		public static implicit operator Map(string text)
		{
			return new StringMap(text);
		}
		public static implicit operator Map(int integer)
		{
			return new Integer32(integer);
		}

		public static Dictionary<Map, Extent> sources = new Dictionary<Map, Extent>(1000, new Comparer());
		// TODO: override this in most maps
		public virtual Extent Source
		{
			get
			{
				Extent source;
				sources.TryGetValue(this, out source);
				if (source == null)
				{
					source = new Extent(new Source(0, 0, 0, ""), new Source(0, 0, 0, ""));
				}
				return source;
				//return null;
			}
			set
			{
				sources[this] = value;
			}
		}
		public abstract int ArrayCount
		{
			get;
		}
		public bool IsString
		{
			get
			{
				return GetString() != null;
			}
		}
		public abstract IEnumerable<Map> Array
		{
			get;
		}
		public abstract Number GetNumber();
		public abstract bool ContainsKey(Map key);
		public abstract IEnumerable<Map> Keys
		{
			get;
		}
		public abstract Map this[Map key]
		{
			get;
			set;
		}
		[Ignore]
		public abstract Map Scope
		{
			get;
			set;
		}
		public class Comparer : IEqualityComparer<Map>
		{
			bool IEqualityComparer<Map>.Equals(Map x, Map y)
			{
				return ReferenceEquals(x, y);
			}
			int IEqualityComparer<Map>.GetHashCode(Map obj)
			{
				return ((object)obj).GetHashCode();
			}
		}

		public virtual Expression Expression
		{
			get
			{
				return null;
			}
			set
			{
			}
		}
		public Expression GetExpression()
		{
			if (Expression == null)
			{
				Expression = CreateExpression();
				if (this.Source != null)
				{
					if (!Meta.Expression.sources.ContainsKey(this.Source.End))
					{
						Meta.Expression.sources[this.Source.End] = new List<Expression>();
					}
					Meta.Expression.sources[this.Source.End].Add(Expression);
					

				}
				Literal literal = Expression as Literal;
				if (literal != null)
				{
					object x = literal.literal.GetExpression();
					if (x != null)
					{
					}
				}
			}
			return Expression;
		}
		public static Dictionary<Map, Type> expressions = new Dictionary<Map, Type>();
		public static Dictionary<Map, Type> statements = new Dictionary<Map, Type>();


		public virtual Expression CreateExpression()
		{
			return GetLiteral() ?? this.GetLastArgument() ?? GetProgram() ?? GetCall() ?? GetSearch()?? GetSelect()??(Expression)GetRoot();
		}
		public virtual Literal GetLiteral()
		{
			if (Count == 1)
			{
				Map literal = this[CodeKeys.Literal];
				if (literal != null)
				{
					return new Literal(literal);
				}
			}
			return null;
		}
		public virtual Call GetCall()
		{
			if (Count == 1)
			{
				Map call = this[CodeKeys.Call];
				if (call != null)
				{
					return new Call(call[1],call[2]);
				}
			}
			return null;
		}
		public virtual LastArgument GetLastArgument()
		{
			if (Count == 1)
			{
				Map lastArgument = this[CodeKeys.LastArgument];
				if (lastArgument != null)
				{
					return new LastArgument(lastArgument);
				}
			}
			return null;
		}
		public virtual Program GetProgram()
		{
			// TODO: add ability to save additional keys in the map
			//if (Count == 1)
			//{
				Map program = this[CodeKeys.Program];
				if (program != null)
				{
					return new Program(program);
				}
			//}
			return null;
		}
		public virtual Root GetRoot()
		{
			if (Count == 1)
			{
				Map root = this[CodeKeys.Root];
				if (root != null)
				{
					return new Root(root);
				}
			}
			return null;
		}
		public virtual Search GetSearch()
		{
			if (Count == 1)
			{
				Map search = this[CodeKeys.Search];
				if (search != null)
				{
					return new Search(search);
				}
			}
			return null;
		}
		public virtual Select GetSelect()
		{
			if (Count == 1)
			{
				Map select = this[CodeKeys.Select];
				if (select != null)
				{
					return new Select(select);
				}
			}
			return null;
		}
		// TODO: remove?
		public Statement GetStatement(Map program, int index)
		{
			foreach (KeyValuePair<Map, Type> pair in statements)
			{
				if (ContainsKey(pair.Key))
				{
					Expression value = this[CodeKeys.Value].GetExpression();
					if (value == null)
					{
						value = this[CodeKeys.Value].GetExpression();
					}
					Statement statement=(Statement)pair.Value.GetConstructors()[0].Invoke(
						new object[] {
							this[pair.Key].GetExpression(),
							value
						}
					);
					statement.Scope = program;
					return statement;
				}
			}
			return null;
		}
		public IEnumerator<KeyValuePair<Map, Map>> GetEnumerator()
		{
			foreach (Map key in Keys)
			{
				yield return new KeyValuePair<Map, Map>(key, this[key]);
			}
		}
	}

	[Serializable]
	public class EmptyMap : Map
	{
		public override Integer GetInteger()
		{
			return Integer32.Zero;
		}
		// TODO: move this to Map???
		public static Map Empty = new EmptyMap(null);
		public override Map Scope
		{
			get
			{
				return null;
			}
			set
			{
			}
		}
		public EmptyMap(Map scope)
		{
			this.Scope = scope;
		}
		public override int GetHashCode()
		{
			return 0;
		}
		public override bool Equals(object obj)
		{
			Map map = obj as Map;
			return map != null && map.Count == 0;
		}
		public override Map this[Map key]
		{
			get
			{
				return null;
			}
			set
			{
				throw new Exception("The method or operation is not implemented.");
			}
		}
		public override IEnumerable<Map> Keys
		{
			get { yield break; }
		}
		public override IEnumerable<Map> Array
		{
			get { yield break; }
		}
		public override int ArrayCount
		{
			get { return 0; }
		}
		public override int Count
		{
			get { return 0; }
		}
		public override bool ContainsKey(Map key)
		{
			return false;
		}
		public override void Append(Map map)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override Map Call(Map arg)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		public override string GetString()
		{
			return "";
		}
		public override Map Copy()
		{
			// TODO: is this correct?
			return this;
			//return new EmptyMap(Scope);
		}
		public override Number GetNumber()
		{
			return Zero;
		}
	}

	[Serializable]
	public class CopyMap : ScopeMap
	{
		public override string ToString()
		{
			return copy.ToString();
		}
		public override string Serialize(bool key)
		{
			return copy.Serialize(key);
		}
		public override Extent Source
		{
			get
			{
				return copy.Source;
			}
			set
			{
				throw new Exception("not implemented");
			}
		}
		public override Map this[Map key]
		{
			get
			{
				return copy[key];
			}
			set
			{
				copy[key] = value;
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				return copy.Keys;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				return copy.Array;
			}
		}
		public override int Count
		{
			get
			{
				return copy.Count;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return copy.ArrayCount;
			}
		}
		public override Map Copy()
		{
			return CopyMap(copy);
		}
		[Ignore]
		private Map copy;
		public CopyMap(Map scope, Map original)
		{
			this.Scope = scope;
			this.copy = original;
		}
		private Expression expression;
		public override Expression Expression
		{
			get
			{
				if (expression != null)
				{
					return expression;
				}
				else
				{
					return copy.Expression;
				}
			}
			set
			{
				expression = value;
			}
		}
		public override Number GetNumber()
		{
			return copy.GetNumber();
		}
		public override bool ContainsKey(Map key)
		{
			return copy.ContainsKey(key);
		}
	}

	/// <summary>
	/// Base map for dictionary maps.
	/// </summary>
	[Serializable]
	public abstract class DictionaryBaseMap : ScopeMap
	{
		public override bool ContainsKey(Map key)
		{
			return this[key] != null;
		}
		public override int Count
		{
			get
			{
				return new List<Map>(Keys).Count;
			}
		}
		// TODO: put this into map?
		public override IEnumerable<Map> Array
		{
			get
			{
				for (int i = 1; ; i++)
				{
					Map m = this[i];
					if (m != null)
					{
						yield return m;
					}
					else
					{
						yield break;
					}
				}
			}
		}
		// TODO: put this into Map?
		public override Number GetNumber()
		{
			if (Count == 0)
			{
				return new Integer32(0);
			}
			else if (this.Count == 1)
			{
				if (this.ContainsKey(EmptyMap.Empty))
				{
					if (this[EmptyMap.Empty].GetNumber() != null)
					{
						return this[EmptyMap.Empty].GetNumber().Add(new Integer32(1));
					}
				}
			}
			return null;
		}
		public override int ArrayCount
		{
			get
			{
				int i = 1;
				while (this.ContainsKey(i))
				{
					i++;
				}
				return i - 1;
			}
		}
	}
	[Serializable]
	public class SingleEntryMap : ScopeMap
	{
		// TODO: is this correct?
		public override Map Copy()
		{
			return this;
		}
		public override Number GetNumber()
		{
			if (key != null && key.Equals(Number.Zero))
			{
				return value.GetNumber().Add(new Integer32(1));
			}
			return null;
		}
		public override bool ContainsKey(Map key)
		{
			return key.Equals(this.key);
		}
		public override int Count
		{
			get
			{
				if (key != null)
				{
					return 1;
				}
				return 0;
			}
		}
		public override int ArrayCount
		{
			get 
			{
				if (key != null && key.Equals(Number.One))
				{
					return 1;
				}
				return 0;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				if (key != null && key.Equals(Number.One))
				{
					yield return value;
				}
				yield break;
			}
		}
		public override IEnumerable<Map> Keys
		{
			get 
			{
				if (key != null)
				{
					yield return key;
				}
				yield break;
			}
		}
		private Map key;
		private Map value;
		public override Map this[Map key]
		{
			get
			{
				if (key.Equals(this.key))
				{
					return value;
				}
				return null;
			}
			set
			{
				this.key = key;
				this.value = value;
			}
		}
	}
	[Serializable]
	public class DictionaryMap : DictionaryBaseMap
	{
		private Expression expression;
		public override Expression Expression
		{
			get
			{
				return expression;
			}
			set
			{
				expression = value;
			}
		}
		public override void CopyInternal(Map map)
		{
			foreach (Map key in map.Keys)
			{
				this.dictionary[key] = map[key];
			}
		}
		public override bool Equals(object obj)
		{
			Map map = obj as Map;
			if (map != null && map.Count == Count)
			{
				foreach (Map key in this.Keys)
				{
					Map otherValue = map[key];
					Map thisValue = this[key];
					if (otherValue == null || otherValue.GetHashCode() != thisValue.GetHashCode() || !otherValue.Equals(thisValue))
					{
						return false;
					}
				}
				return true;
			}
			return false;
		}
		public DictionaryMap()
		{
			this.dictionary = new Dictionary<Map, Map>();
		}
		public DictionaryMap(int capacity)
		{
			this.dictionary = new Dictionary<Map, Map>(capacity);
		}
		public DictionaryMap(Dictionary<Map, Map> dictionary)
		{
			this.dictionary = dictionary;
		}
		public DictionaryMap(params Map[] keysAndValues)
			: this(keysAndValues.Length / 2)
		{
			for (int i = 0; i <= keysAndValues.Length - 2; i += 2)
			{
				this[keysAndValues[i]] = keysAndValues[i + 1];
			}
		}
		public DictionaryMap(System.Collections.Generic.ICollection<Map> list)
			: this(list.Count)
		{
			int index = 1;
			foreach (Map entry in list)
			{
				this[index] = entry;
				index++;
			}
		}
		public DictionaryMap(IEnumerable<Map> list)
			: this()
		{
			foreach (Map map in list)
			{
				this.Append(map);
			}
		}
		public override Map Copy(Map scope)
		{
			return new CopyMap(scope, this);
		}
		public override Map Copy()
		{
			Map clone = new CopyMap(null, this);
			return clone;
		}
		public override void Append(Map map)
		{
			if (map.Scope == null)
			{
				map.Scope = this;
			}
			this[ArrayCount + 1] = map;
		}
		// TODO: remove?
		//public override string Serialize(bool key)
		//{
		//    if (this.Count == 0)
		//    {
		//        return "0";
		//    }
		//    else if (this.IsString)
		//    {
		//        if (key)
		//        {
		//            return this.GetString();
		//        }
		//        else
		//        {
		//            return "\"" + EscapeString(this.GetString()) + "\"";
		//        }
		//    }
		//    else if (this.GetNumber() != null)
		//    {
		//        return this.GetNumber().ToString();
		//    }
		//    return null;
		//}
		private Dictionary<Map, Map> dictionary;
		public override Map this[Map key]
		{
			get
			{
				Map val;
				dictionary.TryGetValue(key, out val);
				return val;
			}
			set
			{
				if (value == null)
				{
					// TODO: fix this
					return;
					//throw new MetaException("Cannot assign null.", null);
				}
				//if (value.Count == 0 && key.Equals(new StringMap("value")))
				//{
				//}
				if (value.Scope == null)
				{
					value.Scope = this;
				}
				dictionary[key] = value;
			}
		}
		public override bool ContainsKey(Map key)
		{
			return dictionary.ContainsKey(key);
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				return dictionary.Keys;
			}
		}
		public override int Count
		{
			get
			{
				return dictionary.Count;
			}
		}
	}
	[Serializable]
	public class AssemblyMap : ScopeMap
	{
		public override string Serialize(bool key)
		{
			return "assembly: " + this.name;
		}
		private Map data;
		public override int Count
		{
			get
			{
				return new List<Map>(Keys).Count;
			}
		}
		public override Map this[Map key]
		{
			get
			{
				return Data[key];
			}
			set
			{
				Data[key] = value;
			}
		}
		private Map Data
		{
			get
			{
				if (data == null)
				{
					data = GetData();
				}
				return data;
			}
		}
		public static Map LoadAssembly(Assembly assembly)
		{
			Map val = new DictionaryMap();
			foreach (Type type in assembly.GetExportedTypes())
			{
				if (type.DeclaringType == null)
				{
					Map selected = val;
					string name;
					if (type.IsGenericTypeDefinition)
					{
						name = type.Name.Split('`')[0];
					}
					else
					{
						name = type.Name;
					}
					selected[type.Name] = new TypeMap(type);
					foreach (ConstructorInfo constructor in type.GetConstructors())
					{
						if (constructor.GetParameters().Length != 0)
						{
							selected[TypeMap.GetConstructorName(constructor)] = new Method(constructor, null, type, constructor);
						}
					}
					if (type.Namespace != null)
					{
						foreach (string n in type.Namespace.Split('.'))
						{
							if (!selected.ContainsKey(n))
							{
								selected[n] = new DictionaryMap();
							}
							selected = selected[n];
						}
					}
					selected[type.Name] = new TypeMap(type);
					foreach (ConstructorInfo constructor in type.GetConstructors())
					{
						if (constructor.GetParameters().Length != 0)
						{
							selected[TypeMap.GetConstructorName(constructor)] = new Method(constructor, null, type, constructor);
						}
					}
				}
			}
			return val;
		}
		private Map GetData()
		{
			return LoadAssembly(Assembly);
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				return Data.Keys;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override bool ContainsKey(Map key)
		{
			return Data.ContainsKey(key);
		}
		public override Number GetNumber()
		{
			return null;
		}
		public override Map Copy()
		{
			return this;
		}
		private Assembly assembly;
		public Assembly Assembly
		{
			get
			{
				if (assembly == null)
				{
					// TODO: check this
					if (name.Contains("Version"))
					{
						assembly = Assembly.Load(name);
					}
					else
					{
						assembly = Assembly.LoadWithPartialName(name);
						if (assembly == null)
						{
							// TODO: fix this
							assembly = Assembly.LoadFrom(Path.Combine(Directory.GetCurrentDirectory(), name + ".dll"));
						}
					}
				}
				return assembly;
			}
		}
		private string name;
		public AssemblyMap(Assembly assembly)
		{
			this.assembly = assembly;
		}
		public AssemblyMap(string name)
		{
			this.name = name;
		}
	}
	[Serializable]
	public class Gac : ScopeMap
	{
		public override Program GetProgram()
		{
			return null;
		}
		public override int Count
		{
			get
			{
				return new List<Map>(Keys).Count;
			}
		}
		List<Map> keys = null;
		public override IEnumerable<Map> Keys
		{
			get
			{
				if (keys == null)
				{
					keys = new List<Map>();
					AssemblyCacheEnum assemblies = new AssemblyCacheEnum(null);
					while (true)
					{
						string name = assemblies.GetNextAssembly();
						if (name == null)
						{
							break;
						}
						if (!name.Contains("DirectX"))
						{
							AssemblyName n = new AssemblyName(name);

							if (!n.Name.EndsWith(".resources"))// && n.Version.Major == 2 && (n.FullName.Contains("b77a5c561934e089") || n.FullName.Contains("b03f5f7f11d50a3a")))
							{
								keys.Add(n.FullName);
								keys.Add(n.Name);
							}
						}
					}
					keys.Add("Meta");
				}
				return keys;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return 0;
			}
		}
		public override bool ContainsKey(Map key)
		{
			if (cache.ContainsKey(key))
			{
				return true;
			}
			else
			{
				return new List<Map>(Keys).Contains(key);
				//try
				//{
				//    AssemblyMap a = new AssemblyMap(key.GetString());
				//    object x = a.Assembly;
				//    cache[key] = a;
				//    return true;
				//}
				//// TODO: do not call Exception
				//catch (Exception e)
				//{
				//    return false;
				//}
			}
			//return new List<Map>(Keys).Contains(key);
		}
		//public override bool ContainsKey(Map key)
		//{
		//    if (cache.ContainsKey(key))
		//    {
		//        return true;
		//    }
		//    else
		//    {
		//        try
		//        {
		//            AssemblyMap a=new AssemblyMap(key.GetString());
		//            object x=a.Assembly;
		//            cache[key] = a;
		//            return true;
		//        }
		//        // TODO: do not call Exception
		//        catch (Exception e)
		//        {
		//            return false;
		//        }
		//    }
		//    //return new List<Map>(Keys).Contains(key);
		//}
		public override Map Copy()
		{
			Map copy = new DictionaryMap();
			foreach (Map key in Keys)
			{
				copy[key] = this[key];
			}
			copy.Scope = Scope;
			return copy;
		}
		public override Number GetNumber()
		{
			return null;
		}
		public static readonly Map gac = new Gac();
		private Gac()
		{
			cache["Meta"] = new AssemblyMap(Assembly.GetExecutingAssembly());
		}
		private Dictionary<Map, Map> cache = new Dictionary<Map, Map>();
		public override Map this[Map key]
		{
			get
			{
				if (!cache.ContainsKey(key))
				{
					if (!ContainsKey(key))
					{
						return null;
					}
					cache[key] = new AssemblyMap(key.GetString());
				}
				return cache[key];
			}
			set
			{
				cache[key] = value;
			}
		}
	}
	[Serializable]
	public class StringMap : ScopeMap
	{
		public override Map Split(Map x)
		{
			return Transform.ToMeta(this.text.Split((char)x.GetInt16()));
			//return base.Split(x);
		}
		public override Map Join(Map map)
		{
			string s = map.GetString();
			if (s != null)
			{
				return new StringMap(this.text + s);
			}
			return base.Join(map);
		}
		//public override Map Join(Map map)
		//{
		//    string s=map.GetString();
		//    if (s != null)
		//    {
		//        return new StringMap(this.text + s);
		//    }
		//    return base.Join(map);
		//}
		private int hashCode;
		private string text;
		public override int GetHashCode()
		{
			return hashCode;
		}
		public override Number GetNumber()
		{
			if (text.Length == 0)
			{
				return Integer32.Zero;
			}
			return null;
		}
		// todo: remove?
		//public override string Serialize(bool key)
		//{
		//    if (key)
		//    {
		//        return text;
		//    }
		//    else
		//    {
		//        return "\"" + EscapeString(text) + "\"";
		//    }
		//}
		public StringMap(string text)
		{
			if (text == null)
			{
				text = "";
			}
			this.text = text;
			if (text.Length == 0)
			{
				hashCode = 0;
			}
			else
			{
				unchecked
				{
					hashCode = int.MaxValue / text.Length + (text[0] % int.MaxValue);
				}
			}
		}
		public override Map this[Map key]
		{
			get
			{
				Integer integer = key.GetInteger();
				if (integer != null)
				{
					if (Library.Greater(integer, Integer32.Zero) && Library.LessEqual(integer, new Integer32(Count)))
					{
						return text[integer.GetInt32() - 1];
					}
				}
				return null;
			}
			set
			{
				throw new Exception("not implemented");
			}
		}
		public override bool Equals(object obj)
		{
			StringMap s = obj as StringMap;
			if (s != null)
			{
				return (text.Length == s.text.Length && s.text.Equals(text));
			}
			return base.Equals(obj);
		}
		public override int Count
		{
			get
			{
				return text.Length;
			}
		}
		public override string GetString()
		{
			return text;
		}
		public override bool ContainsKey(Map key)
		{
			if (key.GetNumber() != null)
			{
				Number number = key.GetNumber();
				return number.Equals(Map.One) &&
					Library.Greater(number, Integer32.Zero) && Library.LessEqual(number, new Integer32(text.Length));
			}
			return false;
		}
		public override int ArrayCount
		{
			get
			{
				return text.Length;
			}
		}
		public override Map Copy()
		{
			return this;
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				foreach (char c in text)
				{
					yield return c;
				}
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				for (int i = 1; i <= text.Length; i++)
				{
					yield return i;
				}
			}
		}
	}
	[Serializable]
	public abstract class Number : Map
	{
		public abstract double GetDouble();
		public abstract Integer64 GetInteger64();
		public abstract Integer32 GetInteger32();
		public abstract Rational GetRational();
		public abstract Number GetSameNumberType(Number a);
		//public abstract bool LessEqual(Number number);
		public abstract Number Multiply(Number b);
		public abstract LargeInteger GetLargeInteger();
		public abstract Number Divide(Number b);
		public abstract int CompareTo(Number number);
		public abstract Integer Numerator
		{
			get;
		}
		public abstract Integer Denominator
		{
			get;
		}
		// TODO: refactor
		public override bool Equals(object obj)
		{
			Number num = obj as Number;
			if (num != null)
			{
				return num.Numerator.Equals(Numerator) && num.Denominator.Equals(Denominator);
			}
			else
			{
				return base.Equals(obj);
			}
		}
		public float GetSingle()
		{
			return (float)GetDouble();
		}
		public Integer Expand(Number b)
		{
			return Numerator.Multiply(LeastCommonMultiple(this, b).Divide(Denominator));
		}
		public static Integer LeastCommonMultiple(Number a, Number b)
		{
			return (a.Denominator).Divide(GreatestCommonDivisor(a.Denominator, b.Denominator)).Multiply(b.Denominator);
		}
		public abstract Number Subtract(Number b);
		public abstract Number Add(Number b);
		public override string GetString()
		{
			return null;
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				yield break;
			}
		}
		public override int Count
		{
			get
			{
				return new List<Map>(Keys).Count;
			}
		}
		public override Map Copy()
		{
			return this;
		}
		public override int ArrayCount
		{
			get 
			{ 
				return 0;
			}
		}
		//public override string Serialize(bool key)
		//{
		//    return this.ToString();
		//}
		public override bool ContainsKey(Map key)
		{
			return new List<Map>(Keys).Contains(key);
		}
		public override Map this[Map key]
		{
			get
			{
				if (ContainsKey(key))
				{
					if (key.Count == 0)
					{
						return Library.Subtract(this.GetNumber(), Number.One);
					}
					else if (key.Equals(NumberKeys.Negative))
					{
						return EmptyMap.Empty;
					}
					else if (key.Equals(NumberKeys.Denominator))
					{
						return Denominator;
					}
					else
					{
						throw new ApplicationException("Error.");
					}
				}
				else
				{
					return null;
				}
			}
			set
			{
				throw new NotImplementedException();
			}
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				if (!this.Equals(Number.Zero))
				{
					yield return EmptyMap.Empty;
				}
				if (Library.Less(this.GetNumber(), Number.Zero))
				{
					yield return NumberKeys.Negative;
				}
				if (!Denominator.Equals(Number.One))
				{
					yield return NumberKeys.Denominator;
				}
			}
		}
		public override Number GetNumber()
		{
			return this;
		}
		public override string ToString()
		{
			if (Denominator.Equals(Number.One))
			{
				return Numerator.ToString();
			}
			else
			{
				return Numerator.ToString() + Parser.fraction + Denominator.ToString();
			}
		}
		public static Integer GreatestCommonDivisor(Integer a, Integer b)
		{
			if (a.Equals(b))
			{
				return a;
			}
			a = a.Absolute();
			b = b.Absolute();
			while (!a.Equals(Integer.Zero) && !b.Equals(Integer.Zero))
			{
				if (a.CompareTo(b)>0)
				//if (a.Greater(b))
				{
					a = a.Modulo(b);
					//a = a % b;
				}
				else
				{
					b = b.Modulo(a);
					//b = b % a;
				}
			}
			if (a.Equals(Integer.Zero))
			{
				return b;
			}
			else
			{
				return a;
			}
		}
	}
	[Serializable]
	public abstract class Integer : Number
	{
		public abstract Integer GetSameIntegerType(Integer i);
		public static IntX smallIntMax = new IntX(int.MaxValue.ToString());
        public static IntX smallIntMin = new IntX(int.MinValue.ToString());

        public static IntX longIntMax = new IntX(long.MaxValue.ToString());
        public static IntX longIntMin = new IntX(long.MinValue.ToString());


		public Integer Negate()
		{
			return new LargeInteger(-this.GetBigInteger());
		}
		public virtual Integer Add(Integer b)
		{
			return new LargeInteger(GetBigInteger()+b.GetBigInteger());
		}
		public virtual Integer Subtract(Integer b)
		{
			return new LargeInteger(this.GetBigInteger()-b.GetBigInteger());
			//return new Rational(Expand(b) - b.Expand(this), LeastCommonMultiple(this, b));
		}
        public static IntX bigZero = new IntX(0);
		// make this abstract?
		public abstract Integer Absolute();
		public override Map Scope
		{
			get
			{
				return null;
			}
			set
			{
			}
		}
		public char GetChar()
		{
			return Convert.ToChar(GetInt32());
		}
		public abstract int Sign();
		public virtual bool Less(Integer b)
		{
			return GetBigInteger()<b.GetBigInteger();
		}
		public virtual bool LessOrEqual(Integer b)
		{
			return GetBigInteger()<=b.GetBigInteger();
		}
        public virtual Integer Modulo(Integer b)
        {
            IntX rest = GetBigInteger()%b.GetBigInteger();
            //BigInteger rest = ints[1];

            //if (rest <=Integer.smallIntMax && rest>=Integer.smallIntMin)
            //{
            //    return new Integer32((int)rest);
            //}
            return new LargeInteger(rest);
        }
        //public virtual Integer Modulo(Integer b)
        //{
        //    BigInteger[] ints = GetBigInteger().divideAndRemainder(b.GetBigInteger());
        //    BigInteger rest = ints[1];

        //    if (rest.compareTo(Integer.smallIntMax) <= 0 && rest.compareTo(Integer.smallIntMin) >= 0)
        //    {
        //        return new Integer32(rest.intValue());
        //    }
        //    return new LargeInteger(rest);
        //}
		//public abstract bool CompareTo(Integer b);
		public virtual int CompareTo(Integer x)
		{
            IntX a=GetBigInteger();
            IntX b=x.GetBigInteger();
            return Compare(a, b);

		}
        public static int Compare(IntX a,IntX b)
        {
            if (a < b)
            {
                return -1;
            }
            else if (a > b)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
		//public abstract bool Greater(Integer b);
		//{
		//    return GetBigInteger().compareTo(b.GetBigInteger()) > 0;//.divide(GetBigInteger()))
		//}

		// TODO: optimize for smallinteger?
		public virtual Integer Multiply(Integer b)
		{
			return new LargeInteger(b.GetBigInteger()*GetBigInteger());
		}
		public virtual Integer Divide(Integer b)
		{
			return new LargeInteger(GetBigInteger() / (b.GetBigInteger()));
		}
		public override Number Multiply(Number b)
		{
			// TODO: use GetInteger?
			Integer integer = b as Integer;
			if (integer != null)
			{
				return new LargeInteger(integer.GetBigInteger()*GetBigInteger());
			}
			return b.GetSameNumberType(this).Multiply(b);
			//return base.Multiply(b);
		}
		public override bool Equals(object obj)
		{
			Map map = obj as Map;
			if (map != null)
			{
				// TODO: use GetInteger method
				Integer integer = map.GetInteger();
				if (integer != null)
				{
					return GetBigInteger().Equals(integer.GetBigInteger());
				}
			}
			return base.Equals(obj);
		}
        public abstract IntX GetBigInteger();
	}
	// TODO: refactor numbers
	[Serializable]
	public class LargeInteger : Integer
	{
		public override int Sign()
		{
            if(integer>0)
            {
                return 1;
            }
            else if(integer<0)
            {
                return -1;
            }
            return 0;
		}
		public override Integer GetSameIntegerType(Integer i)
		{
			return i.GetLargeInteger();
		}
		//public override bool Greater(Integer b)
		//{
		//    return GetBigInteger().compareTo(b.GetBigInteger()) > 0;//.divide(GetBigInteger()))
		//}
		public override Number Add(Number b)
		{
			LargeInteger i = b.GetLargeInteger();
			if (i != null)
			{
				return new LargeInteger(integer+i.integer);
			}
			return b.GetSameNumberType(this).Add(b);
		}
		public override Number Subtract(Number b)
		{
			LargeInteger i = b.GetLargeInteger();
			if (i != null)
			{
				return new LargeInteger(integer-i.integer);
			}
			return b.GetSameNumberType(this).Subtract(b);
		}
		public override int CompareTo(Number number)
		{
			LargeInteger i = number.GetLargeInteger();
			if (i != null)
			{
				return Integer.Compare(integer,i.integer);
			}
			return number.GetSameNumberType(this).CompareTo(number);
		}
        public override Number Divide(Number b)
        {
            LargeInteger i = b.GetLargeInteger();
            if (i != null)
            {
                //IntX results = integer / divideAndRemainder(i.integer);
                if (integer % i.integer == 0)
                {
                    return new LargeInteger(integer / i.integer);
                }
            }
            return new Rational(Numerator.Multiply(b.Denominator), Denominator.Multiply(b.Numerator));
        }
        //public override Number Divide(Number b)
        //{
        //    LargeInteger i = b.GetLargeInteger();
        //    if (i != null)
        //    {
        //        BigInteger[] results = integer.divideAndRemainder(i.integer);
        //        if(results[1].Equals(bigZero))
        //        {
        //            return new LargeInteger(results[0]);
        //        }
        //    }
        //    return new Rational(Numerator.Multiply(b.Denominator), Denominator.Multiply(b.Numerator));
        //}

		public override LargeInteger GetLargeInteger()
		{
			return this;
		}
		public override Integer32 GetInteger32()
		{
			// TODO: determine statically?
			if (integer<=smallIntMax && integer>=smallIntMin)
			{
				return new Integer32(Convert.ToInt32(integer.ToString()));
			}
			//string s = integer.toString(10);
			//int result;
			//if (int.TryParse(s, out result))
			//{
			//    return new Integer32(result);
			//}
			return null;
		}
		public override Integer64 GetInteger64()
		{
			// TODO: optimize?
			string s = this.integer.ToString();//10);
			long result;
			if (long.TryParse(s, out result))
			{
				return new Integer64(result);
			}
			return null;
		}
		//public override bool LessEqual(Number number)
		//{
		//    LargeInteger i = number.GetLargeInteger();
		//    if (i != null)
		//    {
		//        return integer.compareTo(i.integer) <= 0;
		//    }
		//    return number.GetSameNumberType(this).LessEqual(number);
		//}
		public override Rational GetRational()
		{
			return new Rational(this, Integer.One);
		}
		public override Number GetSameNumberType(Number a)
		{
			return a.GetInteger();
		}
		public override Integer Absolute()
		{
			if (this.GetBigInteger()<bigZero)
			{
				return new LargeInteger(-GetBigInteger());
			}
			return this;
		}
		public override string ToString()
		{
			return integer.ToString();
		}
        public override IntX GetBigInteger()
		{
			return integer;
		}
		public override Integer GetInteger()
		{
			return this;
		}
		public override Integer Denominator
		{
			get
			{
				return One;
			}
		}
		public override Integer Numerator
		{
			get
			{
				return this;
			}
		}
		public override double GetDouble()
		{
			return Convert.ToDouble(integer.ToString());
			//return integer.doubleValue();
		}

		//public override long GetRealInt64()
		//{
		//    return Convert.ToInt64(integer.ToString());//.longValue();
		//    //return integer.longValue();
		//}
		//public override long GetInt64()
		//{
		//    return Convert.ToInt64(integer.ToString());
		//    //return integer.longValue();
		//}
        private IntX integer;
		public LargeInteger(int i)
		{
			this.integer = new IntX(i.ToString());
		}
        public LargeInteger(IntX integer)
		{
			this.integer = integer;
			//if (this.integer.compareTo(smallIntMax) < 0)
			//{
			//}
			//if (this.integer.compareTo(longIntMax) < 0)
			//{
			//}
		}
		public LargeInteger(string text)
		{
			this.integer = new IntX(text);
            //if (this.integer<smallIntMax)
            //{
            //}
            //if (this.integer.compareTo(longIntMax) < 0)
            //{
            //}
		}
		public override int GetInt32()
		{
			return Convert.ToInt32(integer.ToString());//.intValue();
		}
	}
	//public class LargeInteger : Integer
	//{
	//    public override string ToString()
	//    {
	//        return integer.ToString();
	//    }
	//    public override BigInteger GetBigInteger()
	//    {
	//        return integer;
	//    }
	//    public override Integer GetInteger()
	//    {
	//        return this;
	//    }
	//    public override Integer Denominator
	//    {
	//        get
	//        {
	//            return One;
	//        }
	//    }
	//    public override Integer Numerator
	//    {
	//        get
	//        {
	//            return this;
	//        }
	//    }
	//    public override double GetDouble()
	//    {
	//        return integer.doubleValue();
	//    }

	//    public override long GetRealInt64()
	//    {
	//        return integer.longValue();
	//    }
	//    public override long GetInt64()
	//    {
	//        return integer.longValue();
	//    }
	//    private BigInteger integer;
	//    public LargeInteger(int i)
	//    {
	//        this.integer = new BigInteger(i.ToString());
	//    }
	//    public LargeInteger(BigInteger integer)
	//    {
	//        this.integer = integer;
	//    }
	//    public LargeInteger(string text)
	//    {
	//        this.integer = new BigInteger(text);
	//    }
	//    public override int GetInt32()
	//    {
	//        return integer.intValue();
	//    }
	//}

	public class Integer64 : Integer
	{
		public override int Sign()
		{
			return integer.CompareTo(0);
		}
		public override Integer GetSameIntegerType(Integer i)
		{
			return i.GetInteger64();
		}
		public override int CompareTo(Integer b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				return integer.CompareTo(i.integer);
			}
			return base.CompareTo(b);
		}
		public override int CompareTo(Number number)
		{
			Integer64 i = number.GetInteger64();
			if (i != null)
			{
				return integer.CompareTo(i.integer);
			}
			return number.GetSameNumberType(this).CompareTo(number);
		}
		public override Number Divide(Number b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				long result = integer / i.integer;
				if (result * i.integer == integer)
				{
					return new Integer64(result);
				}
			}
			return new Rational(Numerator.Multiply(b.Denominator), Denominator.Multiply(b.Numerator));
		}
		public override LargeInteger GetLargeInteger()
		{
			return new LargeInteger(integer.ToString());
		}
		public override Integer64 GetInteger64()
		{
			return this;
		}
		public override Rational GetRational()
		{
			return new Rational(this, Integer.One);
		}
		public override Number GetSameNumberType(Number a)
		{
			return a.GetInteger64();
		}
		public override Integer Modulo(Integer b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				return new Integer64(integer % i.integer);
			}
			return base.Modulo(b);
		}
		//public override bool Greater(Integer b)
		//{
		//    Integer64 i = b.GetInteger64();
		//    if (i != null)
		//    {
		//        return integer > i.integer;
		//    }
		//    return b.GetSameNumberType(this).CompareTo(b)>0;
		//    //return base.Greater(b);
		//}

		//public override bool GreaterOrEqual(Integer b)
		//{
		//    Integer64 i = b.GetInteger64();
		//    if (i != null)
		//    {
		//        return integer >= i.integer;
		//    }
		//    return base.GreaterOrEqual(b);
		//}
		public override bool Less(Integer b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				return integer < i.integer;
			}
			return base.Less(b);
		}
		public override bool LessOrEqual(Integer b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				return integer <= i.integer;
			}
			return base.LessOrEqual(b);
		}
		public override Integer Absolute()
		{
			return new Integer64(Math.Abs(integer));
			//if (this.GetBigInteger().compareTo(bigZero) < 0)
			//{
			//    return new LargeInteger(GetBigInteger().negate());
			//}
			//return this;
		}
		// TODO: remove!
		public override Integer Divide(Integer b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				return new Integer64(integer / i.integer);
			}
			return base.Divide(b);
			//return new LargeInteger(GetBigInteger().divide(b.GetBigInteger()));
		}
		public override Integer Subtract(Integer b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				long result = integer - i.integer;
				if (result + i.integer == integer)
				{
					return new Integer64(result);
				}
			}
			return base.Subtract(b);
		}
		public override Integer Add(Integer b)
		{
			// TODO: combine with normal addition
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				long result = integer + i.integer;
				if (result - i.integer == integer)
				{
					return new Integer64(result);
				}
			}
			return base.Add(b);
		}
		// TODO: fix this
		public override Integer Multiply(Integer b)
		{
			Integer64 i = b.GetInteger64();// Integer64;
			if (i != null)
			{
				//try
				//{
				//unchecked
				//{
				unchecked
				{
					long result = i.integer * integer;
					// TODO: fix this
					if (integer == 0 || (result / integer) == i.integer)
					{
						return new Integer64(result);
					}
					else
					{
					}
				}
				//}
				//}
				//catch (Exception e)
				//{
				//}
			}
			return base.Multiply(b);
		}

		public override Integer32 GetInteger32()
		{
			// TODO: fix this
			return null;
			//return this;
		}
		public override int GetInt32()
		{
			// TODO: remove this
			return (int)integer;
		}
		public override Number Multiply(Number b)
		{
			// TODO: fix this
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				//try
				//{
				//unchecked
				//{
				unchecked
				{
					long result = i.integer * integer;
					// TODO: fix this
					if (integer == 0 || (result / integer) == i.integer)
					{
						return new Integer64(result);
					}
					else
					{
					}
				}
				//}
				//}
				//catch (Exception e)
				//{
				//}
			}
			return base.Multiply(b);
		}
		//public override bool LessEqual(Number number)
		//{
		//    Integer64 i = number.GetInteger64();
		//    if (i != null)
		//    {
		//        return integer <= i.integer;
		//    }
		//    return number.GetSameNumberType(this).LessEqual(number);
		//}
		public override Number Subtract(Number b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				long result = integer - i.integer;
				if(result+i.integer==integer)
				{
					return new Integer64(integer - i.integer);
				}
			}
			return b.GetSameNumberType(this).Subtract(b);
		}
		public override Number Add(Number b)
		{
			Integer64 i = b.GetInteger64();
			if (i != null)
			{
				long result = integer + i.integer;
				if(result-i.integer==integer)
				{
					return new Integer64(result);
				}
			}
			return b.GetSameNumberType(this).Add(b);
			//return base.Add(b);
		}
		public override string ToString()
		{
			return integer.ToString();
		}
		public override bool Equals(object obj)
		{
			Map map = obj as Map;
			if (map != null)
			{
				Integer integer = map.GetInteger();
				if (integer != null)
				{
					Integer64 i = integer.GetInteger64();// as SmallInteger;
					//SmallInteger i = obj as SmallInteger;
					//SmallInteger i = obj as SmallInteger;
					if (i != null)
					{
						return i.integer == this.integer;
					}
				}
			}
			return base.Equals(obj);
		}
        public override IntX GetBigInteger()
		{
			return new IntX(integer.ToString());
		}
		public override Integer GetInteger()
		{
			return this;
		}
		public long integer;
		public Integer64(long integer)
		{
			this.integer = integer;
		}
		public override double GetDouble()
		{
			return integer;
		}
		public override Integer Denominator
		{
			get
			{
				return LargeInteger.One;
			}
		}
		//public override long GetInt64()
		//{
		//    return integer;
		//}
		//public override long GetRealInt64()
		//{
		//    return integer;
		//}
		public override Integer Numerator
		{
			get
			{
				return this;
			}
		}
	}

	[Serializable]
	public class Integer32 : Integer
	{
		public override int Sign()
		{
			return integer.CompareTo(0);
		}
		public override Integer GetSameIntegerType(Integer i)
		{
			return i.GetInteger32();
		}
		public override int CompareTo(Integer b)
		{
			Integer32 i=b.GetInteger32();
			if (i != null)
			{
				return integer.CompareTo(i.integer);
			}
			return b.GetSameIntegerType(this).CompareTo(b);
		}
		public override int CompareTo(Number number)
		{
			Integer32 i = number.GetInteger32();
			if (i != null)
			{
				return integer.CompareTo(i.integer);
			}
			return number.GetSameNumberType(this).CompareTo(number);
		}
		public override Number Divide(Number b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				int result=integer / i.integer;
				// TODO: use modulo?
				if (result * i.integer == integer)
				{
					return new Integer32(result);
				}
				else
				{
					return new Rational(Numerator.Multiply(b.Denominator), Denominator.Multiply(b.Numerator));
				}
			}
			return b.GetSameNumberType(this).Divide(b);
		}
		public override LargeInteger GetLargeInteger()
		{
			return new LargeInteger(integer);
		}
		public override Integer64 GetInteger64()
		{
			return new Integer64(integer);
		}
		public override Rational GetRational()
		{
			return new Rational(this, Integer.One);
		}
		public override Number GetSameNumberType(Number a)
		{
			return a.GetInteger32();
		}
		public override Integer Modulo(Integer b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				return new Integer32(integer % i.integer);
			}
			return base.Modulo(b);
		}
		//public override bool Greater(Integer b)
		//{
		//    Integer32 i = b.GetInteger32();
		//    if (i != null)
		//    {
		//        return integer > i.integer;
		//    }
		//    //return base.Greater(b);
		//    return b.GetSameNumberType(this).CompareTo(b)>0;
		//}

		//public override bool Greater(Number b)
		//{
		//    Integer32 i = b.GetInteger32();
		//    if (i != null)
		//    {
		//        return integer > i.integer;
		//    }
		//    //return base.Greater(b);
		//    return b.GetSameNumberType(this).Greater(b);
		//}
		//public override bool GreaterOrEqual(Integer b)
		//{
		//    Integer32 i = b.GetInteger32();
		//    if (i != null)
		//    {
		//        return integer >= i.integer;
		//    }
		//    return base.GreaterOrEqual(b);
		//}
		//public override bool Less(Integer b)
		//{
		//    Integer32 i = b.GetInteger32();
		//    if (i != null)
		//    {
		//        return integer < i.integer;
		//    }
		//    return base.Less(b);
		//}
		//public override bool LessOrEqual(Integer b)
		//{
		//    Integer32 i = b.GetInteger32();
		//    if (i != null)
		//    {
		//        return integer <= i.integer;
		//    }
		//    return base.LessOrEqual(b);
		//}
		public override Integer Absolute()
		{
			return new Integer32(Math.Abs(integer));
			//if (this.GetBigInteger().compareTo(bigZero) < 0)
			//{
			//    return new LargeInteger(GetBigInteger().negate());
			//}
			//return this;
		}

		public override Integer Divide(Integer b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				return new Integer32(integer / i.integer);
			}
			return base.Divide(b);
			//return new LargeInteger(GetBigInteger().divide(b.GetBigInteger()));
		}
		public override Integer Subtract(Integer b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				int result=integer - i.integer;
				if(result+i.integer==integer)
				{
					return new Integer32(result);
				}
			}
			return base.Subtract(b);
		}
		public override Integer Add(Integer b)
		{
			// TODO: combine with normal addition?
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				int result = integer + i.integer;
				if(result-i.integer==integer)
				{
					return new Integer32(result);
				}
			}
			//Integer64 l=b.GetInteger64();
			//if(
			return base.Add(b);
		}
		// TODO: fix this
		public override Integer Multiply(Integer b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				unchecked
				{
					int result = i.integer * integer;
					// TODO: fix this
					if (integer == 0 || (result / integer) == i.integer)
					{
						return new Integer32(result);
					}
					else
					{
						return new Integer64((long)i.integer * (long)integer);
					}
				}
			}
			else
			{
				return b.GetSameIntegerType(this).Multiply(b);
			}
			//return base.Multiply(b);
		}
		public override Integer32 GetInteger32()
		{
			return this;
		}
		public override int GetInt32()
		{
			return integer;
		}
		public override Number Multiply(Number b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				unchecked
				{
					int result = i.integer * integer;
					// TODO: fix this
					if (integer == 0 || (result / integer) == i.integer)
					{
						return new Integer32(result);
					}
					else
					{
					}
				}
			}
			return base.Multiply(b);
			//return b.GetSameNumberType(this).Multiply(b);
		}
		public override Number Subtract(Number b)
		{
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				int result=integer - i.integer;
				// TODO: fix this
				if (result + i.integer == integer)
				{
					return new Integer32(integer - i.integer);
				}
				else
				{
					return new Integer64((long)integer - (long)i.integer);
				}
			}
			return b.GetSameNumberType(this).Subtract(b);
		}
		public override Number Add(Number b)
		{
			// TODO: use GetInteger32
			Integer32 i = b.GetInteger32();
			if (i != null)
			{
				unchecked
				{
					int result = integer + i.integer;
					if (result - integer == i.integer)
					{
						return new Integer32(result);
					}
				}
			}
			return b.GetSameNumberType(this).Add(b);
		}
		public override string ToString()
		{
			return integer.ToString();
		}
		public override bool Equals(object obj)
		{
			Map map = obj as Map;
			if (map != null)
			{
				Integer integer= map.GetInteger();
				if (integer != null)
				{
					Integer32 i = integer.GetInteger32();// as SmallInteger;
					//SmallInteger i = obj as SmallInteger;
					//SmallInteger i = obj as SmallInteger;
					if (i != null)
					{
						return i.integer == this.integer;
					}
				}
			}
			return base.Equals(obj);
		}
        public override IntX GetBigInteger()
		{
			return new IntX(integer.ToString());
		}
		public override Integer GetInteger()
		{
			return this;
		}
		public int integer;
		public Integer32(int integer)
		{
			this.integer = integer;
		}
		public override double GetDouble()
		{
			return integer;
		}
		public override Integer Denominator
		{
			get
			{
				return LargeInteger.One;
			}
		}
		//public override long GetInt64()
		//{
		//    return integer;
		//}
		//public override long GetRealInt64()
		//{
		//    return integer;
		//}
		public override Integer Numerator
		{
			get
			{
				return this;
			}
		}
	}
	// TODO: remove double
	public class Rational : Number
	{
		public override Number Add(Number b)
		{
			Integer numerator=Expand(b).Add(b.Expand(this));
			Integer denominator=LeastCommonMultiple(this, b);
			if (denominator.Equals(Integer.One))
			{
				return numerator;
			}
			else
			{
				return new Rational(numerator, denominator);
			}
		}
		public override Number Subtract(Number b)
		{
			// TODO: check if result is an integer
			return new Rational(Expand(b).Subtract(b.Expand(this)), LeastCommonMultiple(this, b));
		}
		public override int CompareTo(Number number)
		{
			// TODO: refactor
			return Expand(number).CompareTo(number.Expand(this));
		}
		public override Number  Divide(Number b)
		{
			return new Rational(Numerator.Multiply(b.Denominator), Denominator.Multiply(b.Numerator));
		}

		public override LargeInteger GetLargeInteger()
		{
			if (this.Denominator.Equals(Integer.One))
			{
				return Numerator.GetLargeInteger();
			}
			return null;
		}
		public override Integer32 GetInteger32()
		{
			if (Denominator.Equals(Integer.One))
			{
				return Numerator.GetInteger32();
			}
			return null;
		}
		public override Integer64 GetInteger64()
		{
			if (Denominator.Equals(Integer.One))
			{
				return Numerator.GetInteger64();
			}
			return null;
		}
		public override Number Multiply(Number b)
		{
			// TODO: optimize this?s
			return new Rational(Numerator.Multiply(b.Numerator), Denominator.Multiply(b.Denominator));
		}
		//public override bool LessEqual(Number number)
		//{
		//    return Expand(number).LessOrEqual(number.Expand(this));
		//}
		//public override bool  Greater(Number b)
		//{
		//    return this.Expand(b).Greater(b.Expand(this));
		//}
		public override Rational GetRational()
		{
			return this;
		}
		public override Number GetSameNumberType(Number a)
		{
			return a.GetRational();
		}
		public override Map Scope
		{
			get
			{
				return null;
			}
			set
			{
			}
		}
		public override Integer GetInteger()
		{
			if (Denominator.Equals(One))
			{
				return Numerator;
			}
			return null;
		}
		private Integer numerator;
		private Integer denominator;
		public static Number Parse(string text)
		{
			// TODO: remove try catch
			try
			{
				string[] parts = text.Split('/');
				int numerator = Convert.ToInt32(parts[0]);
				int denominator;
				if (parts.Length > 2)
				{
					denominator = Convert.ToInt32(parts[2]);
				}
				else
				{
					denominator = 1;
				}
				return new Rational(new Integer32(numerator),new Integer32(denominator));
				//return new Rational(numerator, denominator);
			}
			catch (Exception e)
			{
				return null;
			}
		}
		public Rational(string text)
		{
			IntX big = new IntX(text.Replace(".", ""));
			int index = text.IndexOf('.');
			if (index == -1)
			{
				index = 0;
			}
			// TODO: fix this
			IntX b = new IntX(Math.Pow(10, text.Length - index - 1).ToString());
			Init(new LargeInteger(big), new LargeInteger(b));
			//result = new Rational(new LargeInteger(big), new LargeInteger(b));
		}
		public Rational(double d):this(d.ToString(CultureInfo.InvariantCulture))
		{
		}
		public Rational(float d)
			: this(d.ToString(CultureInfo.InvariantCulture))
		{
		}
		private void Init(Integer numerator,Integer denominator)
		{
			Integer greatestCommonDivisor = GreatestCommonDivisor(numerator, denominator);
			if (denominator.Sign() < 0 )//.Less(Zero))
			//if (denominator.Less(Zero))
			{
				numerator = numerator.Negate();
				denominator = denominator.Negate();
			}
			this.numerator = numerator.Divide(greatestCommonDivisor);
			this.denominator = denominator.Divide(greatestCommonDivisor);
		}
		public Rational(Integer numerator, Integer denominator)
		{
			Init(numerator,denominator);
		}
		public override Integer Numerator
		{
			get
			{
				return numerator;
			}
		}
		public override Integer Denominator
		{
			get
			{
				return denominator;
			}
		}
		public Number Clone()
		{
			// TODO: fix thisk
			return this;// new Rational(this);
		}
		public override double GetDouble()
		{
			return numerator.GetDouble() / denominator.GetDouble();
		}
		public override int GetInt32()
		{
			return Convert.ToInt32(numerator.GetDouble() / denominator.GetDouble());
		}
		//public override long GetRealInt64()
		//{
		//    return Convert.ToInt64(numerator.GetDouble() / denominator.GetDouble());
		//}
		//public override long GetInt64()
		//{
		//    return Convert.ToInt64(numerator.GetDouble());
		//}
	}

	[Serializable]
	public class ListMap : ScopeMap
	{
		public override Number GetNumber()
		{
			if (list.Count == 0)
			{
				return Integer32.Zero;
			}
			return null;
		}
		public override Map Copy()
		{
			return DeepCopy();
		}
		public override void Append(Map map)
		{
			if (map.Scope == null)
			{
				map.Scope = this;
			}
			list.Add(map);
		}
		private List<Map> list;
		public ListMap(List<Map> list)
		{
			this.list = list;
		}
		public ListMap(int capacity)
			: this(new List<Map>(capacity))
		{
		}
		public ListMap()
			: this(5)
		{
		}
		public override Map this[Map key]
		{
			get
			{
				if (ContainsKey(key))
				{
					return list[key.GetNumber().GetInt32() - 1];
				}
				return null;
			}
			set
			{
				if (value.Scope == null)
				{
					value.Scope = this;
				}
				int integer = key.GetInt32();
				if (integer >= 1 && integer <= list.Count)
				{
					list[integer - 1] = value;
					return;
				}
				else if (integer == list.Count + 1)
				{
					list.Add(value);
					return;
				}
				throw new Exception("Cannot set key.");
			}
		}
		public override int Count
		{
			get
			{
				return list.Count;
			}
		}
		public override IEnumerable<Map> Array
		{
			get
			{
				return this.list;
			}
		}
		public override int ArrayCount
		{
			get
			{
				return list.Count;
			}
		}
		public override bool ContainsKey(Map key)
		{
			Number number = key.GetNumber();
			return number != null && Library.GreaterEqual(number, Number.One) && Library.LessEqual(number, new Integer32(list.Count));
		}
		public override IEnumerable<Map> Keys
		{
			get
			{
				for (int i = 1; i <= list.Count; i++)
				{
					yield return i;
				}
			}
		}
	}
	public delegate bool Precondition(Parser p);
	public class Parser
	{
		public const string newLine = "\r\n";
		public const char decimalSeparator = '.';
		public const char searchStatement = ':';
		public const char search = '!';
		public const char comment = '/';
		public const char statement = '=';
		public const char programStart = '{';
		public const char programEnd = '}';
		public const char alternativeFunctionEnd = '|';
		//public const char functionEnd = '/';
		public const char arrayStart = '[';
		public const char arrayEnd = ']';
		public const char programSeparator = ';';
		public const char alternativeProgramSeparator = ' ';
		public const char callStart = '(';
		public const char callEnd = ')';
		public const char alternativeCallStart = '?';
		public const char alternativeCallEnd = '%';
		public const char root = '/';
		public const char negative = '-';
		public const char fraction = '/';
		public const char endOfFile = (char)65535;
		public const char lineFeed = '\n';
		public const char carriageReturn = '\r';
		public const char @string = '\"';
		public const char emptyMap = '0';
		public const char lastArgument = '@';
		public const char select = '.';
		public const char character = '\'';
		public const char space = ' ';
		public const char tab = '\t';
		public const char current = '&';
		public const char lookupAnythingStart = '<';
		public const char lookupAnythingEnd = '>';
		public static readonly string integer = "0123456789-";
		public static readonly string lookupStringForbidden =
			"" + tab + current
			+ '\r' + '\n' +
			@string + emptyMap + search + root + callStart + callEnd + programSeparator +
			character + programStart + '*' + '$' + '\\' + lookupAnythingStart + statement +
			arrayStart + '-' + searchStatement + select + ' ' + '-' + arrayStart +
			arrayEnd + '*' + lookupAnythingEnd + programStart + programEnd +
			arrayEnd + alternativeFunctionEnd + ' ' + alternativeCallStart + alternativeCallEnd;
		public static readonly string lookupStringForbiddenFirst = lookupStringForbidden + integer;
		public static Rule Precondition(Precondition precondition, Rule rule)
		{
			rule.precondition = precondition;
			return rule;
		}
		public static Rule Precondition(char c, Rule rule)
		{
			return Precondition(delegate(Parser p) { return p.Look() == c; }, rule);
		}
		public static List<Dictionary<ParserState, CachedResult>> allCached = new List<Dictionary<ParserState, CachedResult>>();
		public struct ParserState
		{
			public override bool Equals(object obj)
			{
				ParserState state = (ParserState)obj;
				return state.index == index && state.FileName == FileName;
			}
			public override int GetHashCode()
			{
				unchecked { return index.GetHashCode() * FileName.GetHashCode(); }
			}
			public ParserState(string fileName, string Text)
			{
				this.index = 0;
				this.FileName = fileName;
				this.Line = 1;
				this.Column = 0;
				this.Text = Text;
				this.Errors = new Error[] { };
			}
			public string Text;
			public string FileName;
			public int index;
			public int Line;
			public int Column;
			public Error[] Errors;
		}
		public Stack<int> defaultKeys = new Stack<int>();
		public ParserState state;
		public Parser(string text, string filePath)
		{
			state = new ParserState(filePath, text + endOfFile);
		}
		public static Rule Program = Precondition(
			programStart,
			DelayedRule(() => Cached(
				Sequence(
					programStart,
					Whitespace,
					Assign(
						CodeKeys.Program,
						Choice(SequenceList(
							Assign(1, AllStatements),
							new FastAction(
								ZeroOrMore(
									Autokey(
										FastSequence(
											OneOrMoreWhitespace,
											new FastAction(AllStatements)
					))))), LiteralRule(Meta.EmptyMap.Empty))),
					Whitespace,
					OptionalError(programEnd)
		))));
		public static Rule Comment = Sequence(
			Sequence(comment,comment),
			StringRule(ZeroOrMoreChars(CharsExcept(carriageReturn.ToString())))
		);
		public static Rule Whitespace = ZeroOrMore(
			Choice(
				Comment,
				lineFeed,
				carriageReturn,
				tab,
				space
		));
		public static Rule OneOrMoreWhitespace = Choice(Sequence(programSeparator, Whitespace), OneOrMore(
				Choice(
					Comment,
					lineFeed,
					carriageReturn,
					tab,
					space
			)));

		public static Rule SimpleWhitespace = ZeroOrMore(
			Choice(
				Comment,
				tab,
				space
		));

		public static Rule Expression = DelayedRule(() =>
			Cached(
				Choice(
					List,
					LiteralExpression,
					Select,
					LastArgument,
					Call,
					Program,
					FunctionProgram,
					Search
		)));
		public static Rule Integer = FastSequence(
			new Action(
				StringRule(OneOrMoreChars(Chars(integer))),
				(Parser p, Map map, ref Map result) =>
				{
					string text = map.GetString();
					int smallInteger;
					if (int.TryParse(text, out smallInteger))
					{
						result = new Integer32(smallInteger);
					}
					else
					{
						result = new LargeInteger(text);
					}
					result.Source = map.Source;
				}
		));
		public static Rule StringLine = StringRule(ZeroOrMoreChars(CharsExcept("\n\r")));
		public static Rule CharacterDataExpression = CharSequence(
			character,
			new FastAction(ReallyOneChar(CharsExcept(character.ToString()))),
			character
		);
		public static Rule String = CharSequence(
			@string,
			new FastAction(StringRule(new StringDelegate(
					delegate(Parser p, ref string s)
					{
						s = "";
						while (true)
						{
							char c = p.Look();
							if (c == endOfFile)
							{
								return false;
							}
							if (c == '"')
							{
								break;
							}
							if (c == '\n')
							{
								p.state.Line++;
							}
							else
							{
								p.state.Column++;
							}
							if (c == '\\')
							{
								p.state.index++;
								char n = p.Look();
								char e;
								switch (n)
								{
									case 'n':
										e = '\n';
										break;
									case 'r':
										e = '\r';
										break;
									case 't':
										e = '\t';
										break;
									case '"':
										e = '"';
										break;
									case '\\':
										e = '\\';
										break;
									default:
										throw new SyntaxException("Invalid escape sequence.", p);
								}
								s += e;
							}
							else
							{
								s += c;
							}
							p.state.index++;
						}
						return true;
					}
				))
			),
			OptionalError(@string)
		);
		public static Rule Decimal = FastSequence(
			new Action(
				StringRule(
					StringSequence(
						OneOrMoreChars(Chars(integer)),
						OneOrMoreChars(Chars(decimalSeparator.ToString())),
						OneOrMoreChars(Chars(integer))
				)),
				(Parser p, Map map, ref Map result) =>
				{
					string text = map.GetString();
					//BigInteger big = new BigInteger(text.Replace(".", ""));
					//int index = text.IndexOf('.');

					//// TODO: fix this
					//BigInteger b = new BigInteger(Math.Pow(10, text.Length - index - 1).ToString());

					////if(!b.compareTo(

					////Rational rational = new Rational(double.Parse(map.GetString(), CultureInfo.InvariantCulture));

					//result = new Rational(new LargeInteger(big), new LargeInteger(b));
					result = new Rational(text);
					result.Source = map.Source;

					//Rational rational = new Rational(double.Parse(map.GetString(), CultureInfo.InvariantCulture));
					//Rational rational = new Rational(double.Parse(map.GetString(), CultureInfo.InvariantCulture));
					//if (rational.GetInteger() != null)
					//{
					//    result = new SmallInteger(rational.GetInt32());
					//    result.Source = map.Source;
					//}
					//else
					//{
					//    result = rational;
					//    result.Source = map.Source;
					//}
				}
				//{
				//    string text = map.GetString();
				//    BigInteger big = new BigInteger(text.Replace(".",""));
				//    int index = text.IndexOf('.');

				//    // TODO: fix this
				//    BigInteger b=new BigInteger(Math.Pow(10, text.Length-index-1).ToString());

				//    //if(!b.compareTo(

				//    //Rational rational = new Rational(double.Parse(map.GetString(), CultureInfo.InvariantCulture));

				//    result = new Rational(new LargeInteger(big),new LargeInteger(b));
				//    result.Source = map.Source;

				//    //Rational rational = new Rational(double.Parse(map.GetString(), CultureInfo.InvariantCulture));
				//    //Rational rational = new Rational(double.Parse(map.GetString(), CultureInfo.InvariantCulture));
				//    //if (rational.GetInteger() != null)
				//    //{
				//    //    result = new SmallInteger(rational.GetInt32());
				//    //    result.Source = map.Source;
				//    //}
				//    //else
				//    //{
				//    //    result = rational;
				//    //    result.Source = map.Source;
				//    //}
				//}
		));
		public static Rule Number = FastSequence(
			new FastAction(Integer),
			new Action(
				Optional(
					CharSequence(
						fraction,
						new FastAction(Integer)
				)),
				(Parser p, Map map, ref Map result) =>
				{
					if (map != null)
					{
						result = new Rational(result.GetInteger(), map.GetInteger());
						result.Source = map.Source;
					}
				}
		));
		//public static Rule Number = FastSequence(
		//    new FastAction(Integer),
		//    new Action(
		//        Optional(
		//            CharSequence(
		//                fraction,
		//                new FastAction(Integer)
		//        )),
		//        (Parser p, Map map, ref Map result) =>
		//        {
		//            if (map != null)
		//            {
		//                result = new Rational(result.GetNumber().GetDouble(), map.GetNumber().GetDouble());
		//                result.Source = map.Source;
		//            }
		//        }
		//));
		public static StringDelegate StringSequence(params StringDelegate[] rules)
		{
			return (Parser parser, ref string s) =>
			{
				s = "";
				ParserState oldState = parser.state;
				foreach (StringDelegate rule in rules)
				{
					string result = null;
					if (rule(parser, ref result))
					{
						s += result;
					}
					else
					{
						parser.state = oldState;
						return false;
					}
				}
				return true;
			};
		}
		public static Rule LookupString = Precondition(
			p => lookupStringForbiddenFirst.IndexOf(p.Look()) == -1,
			Cached(
				StringRule(
					StringSequence(
						SingleCharacter(CharsExcept(lookupStringForbiddenFirst)),
						ZeroOrMoreChars(CharsExcept(lookupStringForbidden))
		))));
		public static Rule Value = DelayedRule(delegate
		{
			return FastSequence(
				Whitespace,
				new FastAction(
					Choice(
						FunctionMap,
						ListMap,
						MapRule,
						String,
						Number,
						CharacterDataExpression
				))
		);
		});
		public static Rule File = FastSequence(new FastAction(Value), Whitespace);
		private static Rule LookupAnything = CharSequence(
			lookupAnythingStart,
			Whitespace,
			new FastAction(Value)
		);


		public static Rule CurrentEntry = FastSequence(
			'&',
			'=',
			new FastAction(Value)
			//new Action(
			//    Value,
			//    (Parser parser, Map map, ref Map result) =>
			//    {
			//        result = new DictionaryMap(result, map);
			//    }
			//)
		);
		public static Rule Entry = FastSequence(
			new FastAction(
				Choice(
					Number,
					LookupString,
					LookupAnything
			)),
			statement,
			Whitespace,
			new Action(
				Value,
				(Parser parser, Map map, ref Map result) =>
				{
					result = new DictionaryMap(result, map);
				}
			),
			Whitespace
		);

		Dictionary<ParserState, string> errors = new Dictionary<ParserState, string>();
		private static Rule Arg = DelayedRule(
			() => Choice(
				List,
				FunctionProgram,
				LiteralExpression,
				Select,
				LastArgument,
				Call,
				Search,
				Program
		));
		public static Rule Call = DelayedRule(
			() => Sequence(
					Whitespace,
					Choice(alternativeCallStart, callStart),
					Whitespace,
					new FastAction(
						MakeCall(
							Choice(Select, Call, LastArgument, LiteralExpression, Search),
							Sequence(
								Optional(' '),
								Whitespace,
								new FastAction(
									Choice(
									Select,
									Call,
									LiteralExpression,
									List,
									Program,
									LastArgument,
									FunctionProgram,
									Search,
									Root))))),
					Whitespace,
					Choice(callEnd, alternativeCallEnd, Error("Missing ')'"))
		));
		//public static Rule Call = DelayedRule(
		//    () => Sequence(
		//            Whitespace,
		//            Choice(alternativeCallStart, callStart),
		//            Whitespace,
		//            Assign(
		//            // TODO: refactor
		//                CodeKeys.Call,
		//                SequenceList(
		//                    Autokey(Choice(Select, Call, LastArgument, LiteralExpression, Search)),
		//                    Whitespace,
		//                    new FastAction(
		//                        ZeroOrMore(
		//                            Autokey(
		//                                Sequence(
		//                                    Optional(' '),
		//                                    Whitespace,
		//                                    new FastAction(
		//                                        Choice(
		//                                        Select,
		//                                        Call,
		//                                        LiteralExpression,
		//                                        List,
		//                                        Program,
		//                                        LastArgument,
		//                                        FunctionProgram,
		//                                        Search))))))
		//                )
		//            ),
		//            Whitespace,
		//            Choice(callEnd, alternativeCallEnd, Error("Missing ')'"))
		//));
		private static Rule Simple(char c, Map literal)
		{
			return CharSequence(c, new FastAction(LiteralRule(literal)));
		}
		private static Rule EmptyMap = Simple(emptyMap, Meta.EmptyMap.Empty);
		private static Rule Current = Simple(current, new DictionaryMap(CodeKeys.Current, Meta.EmptyMap.Empty));
		private static Rule Root = Simple(root, new Root(Meta.EmptyMap.Empty));

		private static Rule LiteralExpression = Precondition(
		    p =>
		    {
				char c=p.Look();
		        switch (c)
		        {
		            case @string:
		            case negative:
		            case '0':
		            case '1':
		            case '2':
		            case '3':
		            case '4':
		            case '5':
		            case '6':
		            case '7':
		            case '8':
		            case '9':
		            case '\'':
		                return true;
		            default:
		                return false;
		        }
		    },
			CreateMap(typeof(Literal),
		            Choice(
		                Decimal,
		                EmptyMap,
		                Number,
		                String,
		                CharacterDataExpression
		)))
		;
		private static Rule LookupAnythingExpression = CharSequence(
			lookupAnythingStart,
			Whitespace,
			new FastAction(Expression),
			OptionalError(lookupAnythingEnd)
		);
		private static Rule LookupStringExpression = Precondition(
			p => lookupStringForbiddenFirst.IndexOf(p.Look()) == -1,
			CreateMap(typeof(Literal),LookupString)
		);
		private static Rule Search = Precondition(
			p =>
			{
				char c = p.Look();
				return c == search || lookupStringForbiddenFirst.IndexOf(c) == -1 || c == lookupAnythingStart;
			},
			Cached(
			CreateMap(
				typeof(Search),
					Choice(
						Prefix(search, Expression),
						Choice(LookupStringExpression, LookupAnythingExpression)
		))));

		public static Rule LastArgument = 
			FastSequence(new Action(
						StringRule(
					StringSequence(
						OneOrMoreChars(Chars(lastArgument.ToString()))
				)),
			(Parser p, Map map, ref Map result) =>
			{
				//if (map != null)
				//{
					string text = map.GetString();
					result = new LastArgument(text.Length-1);
				//}
				//else
				//{
				//    result = new LastArgument(Meta.Maps.EmptyMap.Empty);
				//}
			}
		));	
		//public static Rule LastArgument = Simple(lastArgument, new LastArgument(Meta.Maps.EmptyMap.Empty));
		public static Rule Subselect = CreateMap(
			typeof(Select),
			Sequence(
				select,
				Assign(
					2,
					Choice(
						LookupStringExpression,
						LookupAnythingExpression,
						LiteralExpression,
						Error("Missing subselect")
					)
				)
			)
		);

		// ((asdf.asdf).asdf
		//public static Rule Subselect = CreateMap(
		//    typeof(Select),
		//    Sequence(
		//        select,
		//        Assign(
		//            2,
		//            Choice(
		//                LookupStringExpression,
		//                LookupAnythingExpression,
		//                LiteralExpression,
		//                Error("Missing subselect")
		//            )
		//        )
		//    )
		//);
		//public static Rule Select = DelayedRule(delegate
		//{
		//    // TODO: fix this
		//    return CreateMap(
		//        typeof(Select),
		//        Sequence(
		//            Assign(
		//                1, 
		//                Choice(Call, LastArgument, Root, Search, Program, LiteralExpression)
		//            ),
		//            select,
		//            Assign(
		//                2,
		//                Choice(
		//                    Subselect,
		//                    LookupStringExpression,
		//                    LookupAnythingExpression,
		//                    LiteralExpression,
		//                    Error("Missing subselect")
		//                )
		//            )
		//        )
		//    );
		//});
		public static Rule Select = DelayedRule(delegate
		{
			// TODO: fix this
			return MakeSelect(
				Choice(Call, LastArgument, Root, Search, Program, LiteralExpression),
				Sequence(
					select,
					new FastAction(
						Choice(
                            LastArgument,
							LookupStringExpression,
							LookupAnythingExpression,
							LiteralExpression
							, Error("Missing subselect")
						)
					)
			));
		});

		//public static Rule Select = DelayedRule(delegate
		//{
		//    // TODO: fix this
		//    return Reverse(
		//        CreateMap(
		//            typeof(Select),
		//                Sequence(
		//                    Assign(1, Choice(Call, LastArgument, Root, Search, Program, LiteralExpression)),
		//                    select,
		//                    Assign(2, Choice(
		//                                LookupStringExpression,
		//                                LookupAnythingExpression,
		//                                LiteralExpression,
		//                                Error("Missing subselect")
		//                            )
		//                        )
		//                    )
		//        ),
		//        Subselect,
		//        1
		//    );
		//});


		//public static Rule Select = DelayedRule(delegate
		//{
		//    // TODO: fix this
		//    return Reverse(
		//        Sequence(
		//            Assign(

		//                CodeKeys.Select,
		//                Sequence(
		//                    Assign(1, Choice(Call, LastArgument, Root, Search, Program, LiteralExpression)),
		//                    select,
		//                    Assign(2, Choice(
		//                                LookupStringExpression,
		//                                LookupAnythingExpression,
		//                                LiteralExpression,
		//                                Error("Missing subselect")
		//                            )
		//                        )
		//                    )
		//                )
		//        ),
		//        Subselect,
		//        1
		//    );
		//});
		public static Rule MapRule = Sequence(
			programStart,
			Whitespace,
			new FastAction(
				OneOrMore(
					new Action(
						FastSequence(
							new FastAction(Choice(Entry, CurrentEntry)),
							Whitespace
						),
						(Parser parser, Map map, ref Map result) =>
						{
							foreach (KeyValuePair<Map, Map> pair in map)
							{
								result[pair.Key] = pair.Value;
								pair.Value.Scope = result;
							}
						}
			))),
			OptionalError(programEnd),
			Whitespace
		);
		// TODO: allow empty array
		public static Rule ListMap = CharSequence(
			arrayStart,
			new FastAction(
				PrePost(
					p => { p.defaultKeys.Push(1); },
					SequenceList(
						Whitespace,
						Autokey(Value),
						//Whitespace,
						new FastAction(
							ZeroOrMore(
								Autokey(
									FastSequence(
										//OneOrMoreWhitespace,
										Whitespace,
										new FastAction(FastSequence(Whitespace, new FastAction(Value)))
						)))),
						Whitespace,
						OptionalError(arrayEnd)
					),
					p => p.defaultKeys.Pop()
		)));

		public static Rule ListEntry = new Rule(
			(Parser p, ref Map map) =>
			{
				if (Expression.Match(p, ref map))
				{
					Map key = new Literal(new Integer32(p.defaultKeys.Peek()));
					//Map key = new DictionaryMap(CodeKeys.Literal, new SmallInteger(p.defaultKeys.Peek()));
					key.Source = map.Source;
					map = new DictionaryMap(
						CodeKeys.Key,
						key,
						CodeKeys.Value,
						map
					);
					p.defaultKeys.Push(p.defaultKeys.Pop() + 1);
					return true;
				}
				else
				{
					return false;
				}
			});
		public static Rule List = Precondition(
			arrayStart,
			PrePost(
				p => p.defaultKeys.Push(1),
				Sequence(
					Whitespace,
					arrayStart,

					Assign(
						CodeKeys.Program,
						Choice(
							SequenceList(
								Whitespace,
								Autokey(ListEntry),
								new FastAction(
									ZeroOrMore(
										Autokey(
											FastSequence(
												OneOrMoreWhitespace,
												new FastAction(ListEntry)
								))))
				), LiteralRule(new DictionaryMap()))
				),
				Whitespace,
				arrayEnd
				),
				p => p.defaultKeys.Pop()
		));


		public static Rule DiscardStatement = Sequence(
			Assign(
				CodeKeys.Discard,
				LiteralRule(Meta.EmptyMap.Empty)
			),
			Assign(CodeKeys.Value, Expression)
		);

		public static Rule CurrentStatement =
			Sequence(current, Assign(CodeKeys.Current, LiteralRule(Meta.EmptyMap.Empty)), Optional(statement), Assign(CodeKeys.Value, Expression));

		public static Rule Prefix(Rule pre, Rule rule)
		{
			return FastSequence(pre, new FastAction(rule));
		}

		//public static Rule NormalStatement = 
		//    CreateStatement(
		//    typeof(KeyStatement),
		//        Choice(
		//            CharSequence(
		//                lookupAnythingStart,
		//                Whitespace,
		//                new FastAction(Expression),
		//                OptionalError(lookupAnythingEnd)
		//            ),
		//            Select,
		//            CreateMap(typeof(Literal), LookupString),
		//            Expression
		//        ),
		//        FastSequence(Whitespace, statement, Whitespace),
		//        Expression
		//);

		public static Rule NormalStatement = Sequence(
			Assign(
				CodeKeys.Key,
				Choice(
					CharSequence(
						lookupAnythingStart,
						Whitespace,
						new FastAction(Expression),
						OptionalError(lookupAnythingEnd)
					),
					Select,
					CreateMap(typeof(Literal), LookupString),
					Expression
			)),
			FastSequence(Whitespace, statement, Whitespace),
			Assign(
				CodeKeys.Value,
				Expression
			)
		);

		public static Rule Statement = Sequence(
			Assign(
				CodeKeys.Keys,
				Choice(
					CreateMap(typeof(Literal), LookupString), 
					Expression
			)),
			searchStatement,
			Assign(
				CodeKeys.Value,
				Expression
			)
		);

		public static Rule AllStatements = FastSequence(
			new FastAction(
				Choice(
					CurrentStatement,
					NormalStatement,
					Statement,
					DiscardStatement
			))
		);

		//public static Rule FunctionMap =
		//    CreateMap(
		//    typeof(Program),

			
		//    //Sequence(
		//    //Assign(
		//    //    CodeKeys.Program,
		//        SequenceList(
		//            Autokey(
		//                Sequence(
		//                    Assign(
		//                        CodeKeys.Key,
		//                        CreateMap(typeof(Literal),
		//                                StringRule(ZeroOrMoreChars(CharsExcept(lookupStringForbiddenFirst)))
		//                    )),
		//                    Assign(
		//                        CodeKeys.Value,
		//                        LiteralRule(new LastArgument(Map.Empty)
		//            )))),
		//            Autokey(
		//                Sequence(
		//    // TODO: create CurrentStatement here
		//                    Assign(CodeKeys.Current, LiteralRule(0)),
		//                    Whitespace,
		//                    Choice(alternativeFunctionEnd, functionEnd),
		//                    Assign(CodeKeys.Value, Expression)
		//    )))
		//    //)
		//);


		public static Rule FunctionMap = Sequence(
			Assign(
				CodeKeys.Program,
				SequenceList(
					Autokey(
						Sequence(
							Assign(
								CodeKeys.Key,
								CreateMap(typeof(Literal),
										StringRule(ZeroOrMoreChars(CharsExcept(lookupStringForbiddenFirst)))
							)),
							Assign(
								CodeKeys.Value,
								LiteralRule(new LastArgument(Meta.EmptyMap.Empty)
					)))),
					Autokey(
						Sequence(
			// TODO: create CurrentStatement here
							Assign(CodeKeys.Current, LiteralRule(0)),
							Whitespace,
							alternativeFunctionEnd,
							Assign(CodeKeys.Value, Expression)
			))))
		);

		public static Rule FunctionPart = DelayedRule(
			() => Choice(
				CreateMap(
					typeof(Literal),
						Choice(
						// TODO: use createmap
							Sequence(
								Assign(
									CodeKeys.Program,
									Sequence(
										Autokey(
											Sequence(
												Assign(
													CodeKeys.Key,
													CreateMap(
														typeof(Literal),
														StringRule(ZeroOrMoreChars(CharsExcept(lookupStringForbiddenFirst))
												))),
												Assign(
													CodeKeys.Value,
													LiteralRule(new LastArgument(Meta.EmptyMap.Empty))
										)))
										,
										Autokey(
											Sequence(
												Assign(
													CodeKeys.Current,
													LiteralRule(0)
												),
												Assign(
													CodeKeys.Value,
													Sequence(
														alternativeFunctionEnd,
														Whitespace,
														new FastAction(Expression)
													)
												)
											)
										)
				))))),
				CreateMap(
					typeof(Literal),
						Sequence(
							alternativeFunctionEnd,
							Whitespace,
							new FastAction(Expression)
		))));


		public static Rule FunctionProgram = Sequence(
			new FastAction(FunctionPart)
		);

		public static Rule OptionalError(char c)
		{
			return Choice(c, Error("Missing '" + c + "'"));
		}

		public static Rule Error(string text)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				Error[] errors = new Error[parser.state.Errors.Length + 1];
				parser.state.Errors.CopyTo(errors, 0);
				errors[errors.Length - 1] = new Error(text, new Source(parser.state.Line, parser.state.Column, parser.state.index, parser.state.FileName), parser.state);
				parser.state.Errors = errors;
				return true;
			});
		}

		public class FastAction : Action
		{
			public FastAction(Rule rule)
				: base(rule, delegate { })
			{
			}
			public override bool Execute(Parser parser, ref Map result)
			{
				if (rule.MatchFast(parser, ref result))
				{
					return true;
				}
				return false;
			}
		}

		public class Action
		{
			public static implicit operator Action(char c)
			{
				return StringRule(SingleCharacter(SingleChar(c)));
			}
			public static implicit operator Action(Rule rule)
			{
				return new Action(rule, delegate { });
			}
			protected Rule rule;
			public Action(Rule rule, ActionDelegate action)
			{
				this.rule = rule;
				this.action = action;
			}
			public virtual bool Execute(Parser parser, ref Map result)
			{
				Map map = null;
				if (rule.Match(parser, ref map))
				{
					action(parser, map, ref result);
					return true;
				}
				return false;
			}
			protected ActionDelegate action;
		}

		public static Action Autokey(Rule rule)
		{
			return new Action(rule, (Parser parser, Map map, ref Map result) =>
			{
				if (map != null)
				{
					result.Append(map);
				}
			});
		}
		//public static Action CreateMap(Type mapType, Rule rule)
		//{
		//    return new Action(rule, (Parser parser, Map map, ref Map result) =>
		//    {
		//        // TODO: refactor
		//        if (map != null)
		//        {
		//            result = (Map)mapType.GetConstructor(new Type[]{typeof(Map)}).Invoke(new object[]{map});
		//            //result[key] = map;
		//        }
		//    });
		//}
		public static Action Assign(Map key, Rule rule)
		{
			return new Action(rule, (Parser parser, Map map, ref Map result) =>
			{
				// TODO: refactor
				if (map != null)
				{
					result[key] = map;
				}
			});
		}
		public static Rule MakeCall(Rule start, Rule repeat)
		{
			return new Rule(delegate(Parser parser, ref Map map)
			{
				if (start.Match(parser, ref map))
				{
					Map expression = map;

					//Select result = (Select)map;
					Map sub = null;
					bool matched = false;
					int count = 0;
					List<Map> all = new List<Map>();
					while (repeat.Match(parser, ref sub))
					{
						if (count > 0)
						{
						}
						//if (sub != null)
						//{
						all.Add(sub);
						//expression = new Call(expression.GetExpression(), sub.GetExpression());
						//}
						//map["select"][key] = result;
						//result = (Select)map;
						matched = true;
						count++;
					}
					for (int i = count-1; i >=0; i--)
					{
						expression = new Call(expression.GetExpression(), all[i].GetExpression());// sub.GetExpression());
					}
					if (count == 0)
					{
						expression = new Call(expression.GetExpression(), new Literal(Meta.EmptyMap.Empty));
						matched = true;
					}
					map = expression;
					return matched;
				}
				return false;
			});
		}
		public static Rule MakeSelect(Rule start, Rule repeat)
		{
			return new Rule(delegate(Parser parser, ref Map map)
			{
				if (start.Match(parser, ref map))
				{
					Map expression = map;

					//Select result = (Select)map;
					Map sub=null;
					bool matched = false;
					while (repeat.Match(parser, ref sub))
					{
						//if (sub != null)
						//{
						expression = new Select(expression.GetExpression(), sub!=null?sub.GetExpression():null);
						//}
						//map["select"][key] = result;
						//result = (Select)map;
							matched = true;
					}
					map = expression;
					return matched;
				}
				return false;
			});
		}
		// TODO: make more general
		public static Rule Reverse(Rule start, Rule repeat, Map key)
		{
			return new Rule(delegate(Parser parser, ref Map map)
			{
				if (start.Match(parser, ref map))
				{
					Select result = (Select)map;
					while (repeat.Match(parser, ref map))
					{
						map["select"][key] = result;
						result = (Select)map;
					}
					map = result;
					return true;
				}
				return false;
			});
		}
		public static Rule OneOrMore(Action action)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				bool matched = false;
				while (action.Execute(parser, ref map))
				{
					matched = true;
				}
				return matched;
			});
		}

		public delegate void ActionDelegate(Parser p, Map map, ref Map result);

		public class CachedResult
		{
			public CachedResult(Map map, ParserState state)
			{
				this.map = map;
				this.state = state;
			}
			public Map map;
			public ParserState state;
		}

		public static Rule Cached(Rule rule)
		{
			Dictionary<ParserState, CachedResult> cached = new Dictionary<ParserState, CachedResult>();
			allCached.Add(cached);
			return new Rule((Parser parser, ref Map map) =>
			{
				if (parser.state.Text.Length == parser.state.index + 1)
				{
					return false;
				}
				CachedResult result;
				if (cached.TryGetValue(parser.state, out result))
				{
					map = result.map;
					parser.state = result.state;
					return true;
				}
				ParserState startState = parser.state;
				if (rule.Match(parser, ref map))
				{
					cached[startState] = new CachedResult(map, parser.state);
					return true;
				}
				return false;
			});
		}

		public class Rule
		{
			public Precondition precondition;
			public Rule(ParseFunction parseFunction) { this.parseFunction = parseFunction; }
			public static implicit operator Rule(char c)
			{
				return StringRule(SingleCharacter(SingleChar(c)));
			}
			public bool MatchFast(Parser parser, ref Map map)
			{
				if (precondition != null)
				{
					if (!precondition(parser))
					{
						return false;
					}
				}
				ParserState oldState = parser.state;
				bool matched;
				matched = parseFunction(parser, ref map);
				if (!matched)
				{
					parser.state = oldState;
				}
				else
				{
					if (map != null)
					{
						map.Source = new Extent(
							new Source(oldState.Line, oldState.Column, oldState.index, parser.state.FileName),
							new Source(parser.state.Line, parser.state.Column, parser.state.index, parser.state.FileName));
					}
				}
				return matched;
			}
			public bool Match(Parser parser, ref Map map)
			{
				if (precondition != null)
				{
					if (!precondition(parser))
					{
						return false;
					}
				}
				ParserState oldState = parser.state;
				bool matched;
				Map result = null;
				matched = parseFunction(parser, ref result);
				if (!matched)
				{
					parser.state = oldState;
				}
				else
				{
					if (result != null)
					{
						result.Source = new Extent(
							new Source(oldState.Line, oldState.Column, oldState.index, parser.state.FileName),
							new Source(parser.state.Line, parser.state.Column, parser.state.index, parser.state.FileName));
					}
				}
				map = result;
				return matched;
			}
			private ParseFunction parseFunction;
		}

		public delegate bool CharRule(char next);

		public static CharRule Chars(string chars)
		{
			return new CharRule(next => chars.IndexOf(next) != -1);
		}

		public static CharRule CharsExcept(string characters)
		{
			string chars = characters + endOfFile;
			return new CharRule(c => chars.IndexOf(c) == -1);
		}

		public delegate bool StringDelegate(Parser parser, ref string s);

		public static StringDelegate CharLoop(CharRule rule, int min, int max)
		{
			return delegate(Parser parser, ref string s)
			{
				int offset = 0;
				int column = parser.state.Column;
				int line = 0;
				while ((max == -1 || offset < max) && rule(parser.Look(offset)))
				{
					offset++;
					column++;
					if (parser.Look(offset).Equals(lineFeed))
					{
						line++;
						column = 1;
					}
				}
				s = parser.state.Text.Substring(parser.state.index, offset);
				if (offset >= min && (max == -1 || offset <= max))
				{
					parser.state.index += offset;
					parser.state.Column = column;
					parser.state.Line += line;
					return true;
				}
				return false;
			};
		}

		public static Rule ReallyOneChar(CharRule rule)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				char next = parser.Look();
				bool matched = rule(next);
				if (matched)
				{
					map = next;
					parser.state.index++;
					parser.state.Column++;
					if (next.Equals(lineFeed))
					{
						parser.state.Line++;
						parser.state.Column = 1;
					}
				}
				return matched;
			});
		}

		public static StringDelegate SingleCharacter(CharRule rule)
		{
			return CharLoop(rule, 1, 1);
		}

		public static CharRule SingleChar(char c)
		{
			return new CharRule(next => next.Equals(c));
		}

		public static StringDelegate OneOrMoreChars(CharRule rule)
		{
			return CharLoop(rule, 1, -1);
		}

		public static StringDelegate ZeroOrMoreChars(CharRule rule)
		{
			return CharLoop(rule, 0, -1);
		}

		public static Rule StringRule(StringDelegate del)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				string s = null;
				bool success = del(parser, ref s);
				if (success)
				{
					map = s;
				}
				return success;
			});
		}

		public delegate void PrePostDelegate(Parser parser);

		public static Rule PrePost(PrePostDelegate pre, Rule rule, PrePostDelegate post)
		{
			return new Rule(delegate(Parser parser, ref Map map)
			{
				pre(parser);
				bool matched = rule.Match(parser, ref map);
				post(parser);
				return matched;
			});
		}

		public delegate bool ParseFunction(Parser parser, ref Map map);

		public delegate Rule RuleFunction();

		public static Rule DelayedRule(RuleFunction ruleFunction)
		{
			Rule rule = null;
			return new Rule((Parser parser, ref Map map) =>
			{
				if (rule == null)
				{
					rule = ruleFunction();
				}
				return rule.Match(parser, ref map);
			});
		}

		public static Rule Choice(params Rule[] cases)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				foreach (Rule expression in cases)
				{
					if (expression.Match(parser, ref map))
					{
						return true;
					}
				}
				return false;
			});
		}

		public static Rule Sequence(char c, params Action[] actions)
		{
			List<Action> a = new List<Action>(actions);
			a.Insert(0, c);
			return Precondition(c, Sequence(false, a.ToArray()));
		}

		public static Rule Sequence(params Action[] actions)
		{
			return Sequence(false, actions);
		}
		public static Rule SequenceList(params Action[] actions)
		{
			return Sequence(true, actions);
		}

		public static Rule CharSequence(char c, params Action[] actions)
		{
			List<Action> a = new List<Action>(actions);
			a.Insert(0, c);
			return Precondition(c, FastSequence(a.ToArray()));
		}
		public static Rule FastSequence(params Action[] actions)
		{
			return new Rule((Parser parser, ref Map match) =>
			{
				foreach (Action action in actions)
				{
					if (!action.Execute(parser, ref match))
					{
						match = null;
						return false;
					}
				}
				return true;
			});
		}

		public static Rule CreateStatement(Type type, Rule keyRule,Rule separator, Rule valueRule)
		{
			return new Rule((Parser parser, ref Map match) =>
			{
				Map keyMap = null;
				Map valueMap = null;
				Map separatorMap=null;
				if (keyRule.Match(parser, ref keyMap) && separator.Match(parser,ref separatorMap) && valueRule.Match(parser, ref valueMap))
				{
					Expression keyExpression = keyMap.GetExpression();
					Expression valueExpression = valueMap.GetExpression();
					if (keyExpression == null || valueExpression == null)
					{
					}
					//match = (Map)type.GetConstructor(new Type[] { typeof(Map) }).Invoke(new object[] { x });
					match = (Statement)type.GetConstructors()[0].Invoke(
						new object[] {
							// TODO: remove GetExpression
							keyExpression,
							valueExpression
							//keyMap.GetExpression(),
							//valueMap.GetExpression()
		                }
					);
					object x = match.GetStatement(null,0);
					//result.Scope = match.Scope;
					//match = result;
					return true;
				}
				return false;
			});
		}

		public static Rule CreateMap(Type type,Rule r)
		{
			return new Rule((Parser parser, ref Map match) =>
			{
				if (type.Equals(typeof(Program)))
				{
				}
				Map x=null;
				if (r.Match(parser, ref x))
				{
					if (type.Equals(typeof(Program)))
					{
					}
					match = (Map)type.GetConstructor(new Type[] { typeof(Map) }).Invoke(new object[] { x });
					return true;
				}
				return false;
			});
		}

		public static Rule Sequence(bool list, params Action[] actions)
		{
			return new Rule((Parser parser, ref Map match) =>
			{
				if (list)
				{
					match = new ListMap();
				}
				else
				{
					match = new DictionaryMap();
				}
				foreach (Action action in actions)
				{
					if (!action.Execute(parser, ref match))
					{
						match = null;
						return false;
					}
				}
				return true;
			});
		}

		public static Rule LiteralRule(Map literal)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				map = literal;
				return true;
			});
		}
		public static Rule ZeroOrMore(Action action)
		{
			return new Rule((Parser parser, ref Map map) =>
			{
				while (action.Execute(parser, ref map)) ;
				return true;
			});
		}
		public static Rule Optional(Rule rule)
		{
			return new Rule((Parser parser, ref Map match) =>
			{
				rule.Match(parser, ref match);
				return true;
			});
		}
		private char Look(int offset)
		{
			return state.Text[state.index + offset];
		}
		private char Look()
		{
			return Look(0);
		}
		public static Map Parse(string file)
		{
			return ParseString(System.IO.File.ReadAllText(file), file);
		}
		public static Map ParseExpression(string text, string fileName)
		{
			Parser parser = new Parser(text, fileName);
			Map result = null;
			Expression.Match(parser, ref result);
			if (parser.state.index != parser.state.Text.Length - 1 || parser.state.Errors.Length != 0)
			{
				string t = "";
				if (parser.state.index != parser.state.Text.Length - 1)
				{
					t += "Expected end of file. " + new Source(parser.state.Line, parser.state.Column, parser.state.index, parser.state.FileName).ToString() + "\n";
				}
				foreach (Error error in parser.state.Errors)
				{
					t += error.Text + error.Source.ToString() + "\n";
				}
				throw new SyntaxException(t, parser);
			}
			foreach (Dictionary<ParserState, CachedResult> cached in allCached)
			{
				cached.Clear();
			}
			return result;
		}
		public static Map ParseString(string text, string fileName)
		{
			Parser parser = new Parser(text, fileName);
			Map result = null;
			File.Match(parser, ref result);
			if (parser.state.index != parser.state.Text.Length - 1 || parser.state.Errors.Length != 0)
			{
				string t = "";
				if (parser.state.index != parser.state.Text.Length - 1)
				{
					t += "Expected end of file. " + new Source(parser.state.Line, parser.state.Column, parser.state.index, parser.state.FileName).ToString() + "\n";
				}
				foreach (Error error in parser.state.Errors)
				{
					t += error.Text + error.Source.ToString() + "\n";
				}
				throw new SyntaxException(t, parser);
			}
			foreach (Dictionary<ParserState, CachedResult> cached in allCached)
			{
				cached.Clear();
			}
			if (result == null)
			{
				throw new MetaException("Unable to parse file " + fileName, null);
			}
			result.Scope = Versions.versions;
			return result;
		}
	}
	// TODO: remove?
	public class SyntaxException : MetaException
	{
		public SyntaxException(string message, Parser parser)
			: base(message, new Source(parser.state.Line, parser.state.Column, parser.state.index, parser.state.FileName))
		{
		}
	}
	[Serializable]
	public class Source
	{
		public bool Less(Source source)
		{
			return Line < source.Line || (Line == source.Line && Column < source.Column);
		}
		public bool Greater(Source source)
		{
			return Line > source.Line || (Line == source.Line && Column > source.Column);
		}
		public override string ToString()
		{
			return FileName + ", " + "line " + Line + ", column " + Column;
		}
		public int Line
		{
			get;
			set;
		}
		public int Column
		{
			get;
			set;
		}
		public int Index
		{
			get;
			set;
		}
		public string FileName
		{
			get;
			set;
		}
		public Source(int line, int column, int index, string fileName)
		{
			this.Line = line;
			this.Column = column;
			this.Index = index;
			this.FileName = fileName;
		}
		public override int GetHashCode()
		{
			unchecked
			{
				return Line.GetHashCode() * Column.GetHashCode() * FileName.GetHashCode();
			}
		}
		public int CompareTo(Source source)
		{
			int line = Line.CompareTo(source.Line);
			if (line != 0)
			{
				return line;
			}
			else
			{
				return Column.CompareTo(source.Column);
			}
		}
		public override bool Equals(object obj)
		{
			Source source = obj as Source;
			return source != null && Line == source.Line && Column == source.Column && FileName == source.FileName;
		}
	}
	[Serializable]
	public class Extent
	{
		public readonly Source Start;
		public readonly Source End;
		public Extent(Source start, Source end)
		{
			this.Start = start;
			this.End = end;
		}
		public override int GetHashCode()
		{
			unchecked
			{
				return Start.GetHashCode() * End.GetHashCode();
			}
		}
		public override bool Equals(object obj)
		{
			Extent extent = obj as Extent;
			return extent != null && Start.Equals(extent.Start) && End.Equals(extent.End);
		}
	}
	public class Serialization
	{
		public delegate string Serializer(Map map);
		public static string Exists(Map key,Map map,Serializer serializer)
		{
			if (map.ContainsKey(key))
			{
				return serializer(map[key]);
			}
			return "";
		}
		public static string Serialize(Map map)
		{
			return Serialize(map, 0).Trim();
		}
		private static string Number(Map map)
		{
			return map.GetNumber().ToString();
		}
		private static string StatementMap(Map map,int indentation)
		{
			string s;
			if (map.ContainsKey(CodeKeys.Current))
			{
				s = Parser.current.ToString() + Parser.statement.ToString()+ CodeMap(map[CodeKeys.Value],indentation,false)+Parser.newLine;
			}
			else if (map.ContainsKey(CodeKeys.Discard))
			{
				s = CodeMap(map[CodeKeys.Value], indentation,false) + Parser.newLine;
			}
			else if (map.ContainsKey(CodeKeys.Key))
			{
				s = CodeMap(map[CodeKeys.Key], indentation,true) + Parser.statement + CodeMap(map[CodeKeys.Value],indentation,false);
			}
			else if (map.ContainsKey(CodeKeys.Keys))
			{
				s = CodeMap(map[CodeKeys.Keys], indentation,true) + Parser.searchStatement + CodeMap(map[CodeKeys.Value],indentation,false);
			}
			else
			{
				throw new Exception("invalid statement");
			}
			return  Indentation(indentation) + s + Parser.newLine;
		}
		private static bool CodeMap(Map map, int indentation,bool key,out string result)
		{
			result = CodeMap(map,indentation,key);
			return result != "";
		}
		private static string FunctionMap(Map map,int indentation)
		{
			if (map.Count == 2 && map.ArrayCount == 2)
			{

				if (map[1].Count == 2 
					&& map[1].ContainsKey(CodeKeys.Key) 
					&& map[1][CodeKeys.Key].ContainsKey(CodeKeys.Literal) 
					&& map[1][CodeKeys.Key][CodeKeys.Literal].IsString 
					&& map[1][CodeKeys.Value].ContainsKey(CodeKeys.LastArgument)
					&& map[1][CodeKeys.Value][CodeKeys.LastArgument].Equals(EmptyMap.Empty)
				)
				//if (map[1].Count == 2 && map[1].ContainsKey(CodeKeys.Key) && map[1][CodeKeys.Key].ContainsKey(CodeKeys.Literal) && map[1][CodeKeys.Key][CodeKeys.Literal].IsString)
				{
					string text = map[1][CodeKeys.Key][CodeKeys.Literal].GetString() + Parser.alternativeFunctionEnd;
					if (map[2].Count == 2 && map[2].ContainsKey(CodeKeys.Current) && map[2][CodeKeys.Current].Count == 0 && map[2].ContainsKey(CodeKeys.Value))
					{
						string result;
						if (CodeMap(map[2][CodeKeys.Value], indentation,false,out result))
						{
							return text + result;
						}
					}
				}
			}
			return "";
		}
		private static string CodeMap(Map map,int indentation,bool k)
		{
			if (map.Count == 0)
			{
				return "";
			}
			Map key = new List<Map>(map.Keys)[0];
			if (map.Count == 1 && key.Equals(CodeKeys.Call))
			{
				return Parser.callStart
					+ string.Join(" ", new List<Map>(map[key].Array).ConvertAll(delegate(Map a) { return CodeMap(a, indentation, false); }).ToArray()) 
					+ Parser.callEnd;
			}
			else if (map.Count == 1 && key.Equals(CodeKeys.LastArgument))
			{
				return Parser.lastArgument.ToString();
			}
			else if (map.Count == 1 && key.Equals(CodeKeys.Literal))
			{
				string result;
				if (CodeMap(map[key], indentation,false, out result))
				{
					return result;
				}
				//return CodeMap(map[key],indentation,k);//.Serialize();
				return map[key].Serialize(k);
			}
			else if (map.Count == 1 && key.Equals(CodeKeys.Program))
			{
				Map program = map[key];
				string functionMap = FunctionMap(program,indentation);
				if (functionMap != "")
				{
					return functionMap;
				}
				else
				{
					var prog=map.GetProgram();
					var statements = new List<Map>(map[key].Array);
					if (statements.Count == 5)
					{
					}
					List<Map> array = new List<Map>();
					int counter = 1;
					foreach (var x in prog.statementList)
					{
						var statement = x as KeyStatement;
						if (statement == null)
						{
							break;
						}
						var literal = statement.key as Literal;
						if (literal == null)
						{
							break;
						}
						if (literal.literal.Equals(new Integer32(counter)))
						{
							array.Add(statement.value);
						}
						else
						{
							break;
						}
						counter++;
					}
					if (array.Count == statements.Count)
					{
						return Parser.arrayStart + Parser.newLine + string.Join(Parser.newLine, array.ConvertAll( delegate(Map a)
						{
							return Indentation(indentation + 1) + CodeMap(a, indentation + 1, false);
						}).ToArray()) + Parser.newLine + Indentation(indentation) + Parser.arrayEnd;
					}
					return Parser.programStart + Parser.newLine + string.Join("", statements.ConvertAll(
						delegate(Map a) { 
							return StatementMap(a,indentation+1); }).ToArray()) + Indentation(indentation) + Parser.programEnd;
				}
			}
			else if (key.Equals(CodeKeys.Root) && map[key].Count == 0)
			{
				return Parser.root.ToString();
			}
			else if (key.Equals(CodeKeys.Search))
			{
				if (map[key].Count == 1 && map[key].ContainsKey(CodeKeys.Literal))
				{
					Map literal = map[key][CodeKeys.Literal];
					if (literal.IsString && !literal.GetString().Contains(Parser.lookupStringForbiddenFirst))
					{
						return literal.GetString();
					}
					// TODO: refactor
					return Parser.lookupAnythingStart + Serialize(literal, indentation) + Parser.lookupAnythingEnd;
				}
				return Parser.lookupAnythingStart + CodeMap(map[key], indentation,false) + Parser.lookupAnythingEnd;
				//return "<" + CodeMap(map[key], indentation) + ">";
			}
			else if (key.Equals(CodeKeys.Select))
			{
				return string.Join(Parser.select.ToString(), new List<Map>(map[key].Array).ConvertAll(delegate(Map a) {
					return a.Count == 1 && a.ContainsKey(CodeKeys.Literal) && a[CodeKeys.Literal].IsString && !a[CodeKeys.Literal].GetString().Contains(Parser.lookupStringForbiddenFirst) ? a[CodeKeys.Literal].GetString() : CodeMap(a,indentation,false); 
				}).ToArray());
			}
			else
			{
				return "";
			}
		}
		private static string Serialize(Map map, int indentation)
		{
			string result;
			if (map == null)
			{
				return "null";
			}
			else if (map is DirectoryMap)
			{
				return "DirectoryMap (" + ((DirectoryMap)map).path.ToString() + ")";
			}
			else if (map.Count == 0)
			{
				return Parser.emptyMap.ToString();
			}
			else if (map.IsString)
			{
				return String(map, indentation);
			}
			if (map is DotNetMap)
			{
				return map.ToString();
			}
			else if (map.GetNumber() != null)
			{
				return Number(map);
			}
			else if (map.IsString)
			{
				return String(map, indentation);
			}
			else if (map.Count == 1 && CodeMap(map, indentation, false, out result))
			{
				return result;
			}
			else
			{
				return Map(map, indentation);
			}
		}
		private static string Map(Map map, int indentation)
		{
			string text;
			if (indentation < 0)
			{
				text = "";
			}
			else
			{
				text = Parser.programStart + Environment.NewLine;
			}
			foreach (KeyValuePair<Map, Map> entry in map)
			{
				if (entry.Value == null)
				{
					object asdf = map[entry.Key];
				}
				text += Entry(indentation, entry);
			}
			text += Parser.programEnd;
			return text;
		}
		private static string Entry(int indentation, KeyValuePair<Map, Map> entry)
		{
			return (Indentation(indentation + 1)
				+ Key(indentation, entry) +
				Parser.statement.ToString() +
				Serialize(entry.Value, indentation + 1)
				+ Parser.newLine).TrimEnd('\r', '\n')
				+ Parser.newLine;
		}
		private static string Root()
		{
			return Parser.root.ToString();
		}
		private static string Trim(string text)
		{
			return text.TrimEnd('\n', '\r');
		}
		private static string NewLine()
		{
			return Environment.NewLine;
		}
		private static string Key(int indentation, KeyValuePair<Map, Map> entry)
		{
			if (entry.Key.Count != 0 && entry.Key.IsString)
			{
				string key = entry.Key.GetString();
				if (key.IndexOfAny(Parser.lookupStringForbidden.ToCharArray()) == -1 && entry.Key.GetString().IndexOfAny(Parser.lookupStringForbiddenFirst.ToCharArray()) != 0)
				{
					return entry.Key.GetString();
				}
			}
			return Serialize(entry.Key, indentation + 1);
		}
		private static string String(Map map, int indentation)
		{
		    string text = map.GetString();
		    if (text.Contains("abc"))
		    {
		    }
		    text = text.Replace("\"","\\\"").Replace("\\","\\\\");
		        //    e = '"';
		        //    break;
		        //case '\\':
		        //    e = '\\';
		        //    break;
		        //default:
		        //    throw new SyntaxException("Invalid escape sequence.", p);
		    //}
		    //if (text.Contains("\"") || text.Contains("\n"))
		    //{
		    //    string result = "\"" + Environment.NewLine;
		    //    foreach (string line in text.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None))
		    //    {
		    //        result += Indentation(indentation) + "\t" + line + Environment.NewLine;
		    //    }
		    //    return result.Trim('\n', '\r') + Environment.NewLine + Indentation(indentation) + "\"";
		    //}
		    //else
		    //{
		        return "\"" + text + "\"";
		    //}
		}
		private static string Indentation(int indentation)
		{
			return "".PadLeft(Math.Max(0, indentation), '\t');
		}
	}

	public class Error
	{
		public Parser.ParserState State
		{
			get;
			set;
		}
		public string Text
		{
			get;
			set;
		}
		public Source Source
		{
			get;
			set;
		}
		public Error(string text, Source source, Parser.ParserState state)
		{
			this.State = state;
			this.Text = text;
			this.Source = source;
		}
	}
	public class CodeKeys
	{
		static CodeKeys()
		{

			CodeKeys bla = new CodeKeys();
			Map.statements[CodeKeys.Keys] = typeof(SearchStatement);
			Map.statements[CodeKeys.Current] = typeof(CurrentStatement);
			Map.statements[CodeKeys.Key] = typeof(KeyStatement);
			Map.statements[CodeKeys.Discard] = typeof(DiscardStatement);

			//Map.expressions[CodeKeys.Call] = typeof(Call);
			Map.expressions[CodeKeys.Program] = typeof(Program);
			//Map.expressions[CodeKeys.Literal] = typeof(Literal);
			Map.expressions[CodeKeys.Select] = typeof(Select);
			//Map.expressions[CodeKeys.Root] = typeof(Root);
			//Map.expressions[CodeKeys.Search] = typeof(Search);
		}
		public static readonly Map LastArgument = "lastArgument";
		public static readonly Map Discard = "discard";
		public static readonly Map Key = "key";
		public static readonly Map Root = "root";
		public static readonly Map Search = "search";
		public static readonly Map Current = "current";
		public static readonly Map Scope = "scope";
		public static readonly Map Literal = "literal";
		public static readonly Map Call = "call";
		public static readonly Map Select = "select";
		public static readonly Map Program = "program";
		// TODO: rename or remove
		public static readonly Map Keys = "keys";
		public static readonly Map Value = "value";
	}
	public class NumberKeys
	{
		public static readonly Map Negative = "negative";
		public static readonly Map Denominator = "denominator";
	}
	public class IgnoreAttribute : Attribute
	{
	}
	public abstract class TestRunner
	{
		public abstract class Test
		{
			public bool RunTest()
			{
				int level;
				Console.Write(this.GetType().Name + "...");
				DateTime startTime = DateTime.Now;
				object result = GetResult(out level);
				TimeSpan duration = DateTime.Now - startTime;
				string testDirectory = Path.Combine(Interpreter.TestPath,this.GetType().Name);
				string resultPath = Path.Combine(testDirectory,"result.txt");
				string checkPath = Path.Combine(testDirectory,"check.txt");
				Directory.CreateDirectory(testDirectory);
				if(!File.Exists(checkPath))
				{
					File.Create(checkPath).Close();
				}
				StringBuilder stringBuilder = new StringBuilder();
				Serialize(result,"",stringBuilder,level);
				File.WriteAllText(resultPath,stringBuilder.ToString(),Encoding.UTF8);
				string successText;
				bool success = File.ReadAllText(resultPath).Equals(File.ReadAllText(checkPath));
				if(success)
				{
					successText = "succeeded";
				}
				else
				{
					successText = "failed";
				}
				Console.WriteLine(" " + successText + "  " + duration.TotalSeconds.ToString() + " s");
				return success;
			}
			public abstract object GetResult(out int level);
		}
		public void Run()
		{
			bool allTestsSucessful = true;
			foreach(Type testType in this.GetType().GetNestedTypes())
			{
				if(testType.IsSubclassOf(typeof(Test)))
				{
					Test test = (Test)testType.GetConstructor(new Type[] { }).Invoke(null);
					if(!test.RunTest())
					{
						allTestsSucessful = false;
					}
				}
			}
			if(!allTestsSucessful)
			{
				Console.ReadLine();
			}
		}
		public const char indentationChar = '\t';
		private static bool UseToStringMethod(Type type,object obj)
		{
			if(obj is string)
			{
				return true;
			}
			if(obj is IEnumerable)
			{
				return false;
			}
			return (!type.IsValueType || type.IsPrimitive) &&
				Assembly.GetAssembly(type) != Assembly.GetExecutingAssembly();
		}
		private static bool UseProperty(PropertyInfo property,int level)
		{
			return Assembly.GetAssembly(property.DeclaringType) != Assembly.GetExecutingAssembly();
		}
		public static void Serialize(object obj,string indent,StringBuilder builder,int level)
		{
			if(obj == null)
			{
				builder.Append(indent + "null\n");
			}
			else if(UseToStringMethod(obj.GetType(),obj))
			{
				builder.Append(indent + "\"" + obj.ToString() + "\"" + "\n");
			}
			else
			{
				string specialEnumerableSerializationText;
				if(obj is ISerializeEnumerableSpecial && (specialEnumerableSerializationText = ((ISerializeEnumerableSpecial)obj).Serialize(false)) != null)
				{
					builder.Append(indent + specialEnumerableSerializationText + "\n");
				}
				else if(obj is System.Collections.IEnumerable)
				{
					foreach(object entry in (System.Collections.IEnumerable)obj)
					{
						builder.Append(indent + "Entry (" + entry.GetType().Name + ")\n");
						Serialize(entry,indent + indentationChar,builder,level);
					}
				}
				else
				{
					foreach(PropertyInfo property in obj.GetType().GetProperties())
					{
						if(property.GetCustomAttributes(typeof(IgnoreAttribute),true).Length == 0)
						{
							//inline this
							if(UseProperty((PropertyInfo)property,level))
							{
								object val = property.GetValue(obj,null);
								builder.Append(indent + property.Name);
								if(val != null)
								{
									builder.Append(" (" + val.GetType().Name + ")");
								}
								builder.Append(":\n");
								Serialize(val,indent + indentationChar,builder,level);
							}
						}
					}
					foreach(FieldInfo field in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance))
					{
						if(field.GetCustomAttributes(typeof(IgnoreAttribute),true).Length == 0)
						{
							object val = field.GetValue(obj);
							builder.Append(indent + field.Name);
							if(val != null)
							{
								builder.Append(" (" + val.GetType().Name + ")");
							}
							builder.Append(":\n");
							Serialize(val,indent + indentationChar,builder,level);
						}
					}
				}
			}
		}
	}
	public class MetaTest : TestRunner
	{
		public static int Leaves(Map map)
		{
			int count = 0;
			foreach(KeyValuePair<Map,Map> pair in map)
			{
				if(pair.Value.GetNumber() != null)
				{
					count++;
				}
				else
				{
					count += Leaves(pair.Value);
				}
			}
			return count;
		}
		public static string TestPath
		{
			get
			{
				return Path.Combine(Interpreter.InstallationPath,"Test");
			}
		}
		public class Serialization : Test
		{
			public override object GetResult(out int level)
			{
				level = 1;
				string fileName = Path.Combine(Interpreter.InstallationPath, @"Test\basicTest.meta");
				//string fileName = Path.Combine(Interpreter.InstallationPath, @"..\..\Test\basicTest.meta");
				string text = File.ReadAllText(fileName);
				return Meta.Serialization.Serialize(Parser.ParseString(text, fileName));
			}
		}

		//public class BasicExpression : Test
		//{
		//    public override object GetResult(out int level)
		//    {
		//        level = 2;
		//        string path = Path.Combine(Interpreter.TestPath, @"basicTest.meta");
		//        Directory.SetCurrentDirectory(Path.GetDirectoryName(path));
		//        Map callable = Parser.Parse(path);
		//        callable.Scope = Versions.versions;// Gac.gac["library"];
		//        //callable.Scope = Gac.gac["library"];
		//        //LiteralExpression gac = new LiteralExpression(Gac.gac);
		//        //LiteralExpression lib = new LiteralExpression(Gac.gac["library"]);
		//        //lib.Parent = gac;
		//        //lib.Statement = new LiteralStatement(gac);
		//        //callable.GetExpression().Statement = new LiteralStatement(lib);
		//        //callable.Expression.Parent = lib;
		//        //Gac.gac.Scope = new DirectoryMap(Path.GetDirectoryName(path));
		//        //callable.GetExpression();
		//        return callable.GetExpression();
		//    }
		//}




		public class Basic : Test
		{
			public override object GetResult(out int level)
			{
				level = 2;
				return Interpreter.Run(Path.Combine(Interpreter.TestPath, @"basicTest.meta"), new DictionaryMap(1, "first argument", 2, "second argument"), true);
			}
		}

		public class Library : Test
		{
			public override object GetResult(out int level)
			{
				level = 2;
				return Interpreter.Run(Path.Combine(Interpreter.TestPath, @"libraryTest.meta"), new DictionaryMap());
			}
		}

		public class Documentation : Test
		{
			public override object GetResult(out int level)
			{
				StringMap examples = new StringMap("examples");
				level = 2;
				Map m = Parser.Parse(Path.Combine(Path.GetDirectoryName(Interpreter.LibraryPath), @"documentation.meta"));
				Map result = new DictionaryMap();
				foreach (var x in m)
				{
					if (x.Value.ContainsKey(examples))
					{
						List<Map> array = new List<Map>();
						foreach (var a in x.Value[examples].Array)
						{
							var func=a["code"];
							if (func != null)
							{
								func.Scope = Versions.versions;
								array.Add(func.Call(Map.Empty));
							}
						}
						result[x.Key] = new ListMap(array);
					}
					//result[x.Key]=.Call
				}
				return result;
			}
		}

		//public class Performance : Test
		//{
		//    public override object GetResult(out int level)
		//    {
		//        level = 2;
		//        return Interpreter.Run(Path.Combine(Interpreter.TestPath, @"performanceTest.meta"), new DictionaryMap(), true);
		//    }
		//}
		//public class Throws : Test
		//{
		//    public override object GetResult(out int level)
		//    {
		//        level = 2;
		//        return Interpreter.Run(Path.Combine(Interpreter.TestPath, @"ddthrows.meta"), new DictionaryMap());
		//    }
		//}

		//public class OptimizedExpression : Test
		//{
		//    public override object GetResult(out int level)
		//    {
		//        level = 2;
		//        string path = Path.Combine(Interpreter.TestPath, @"performanceTest.meta");
		//        Directory.SetCurrentDirectory(Path.GetDirectoryName(path));
		//        Map callable = Parser.Parse(path);
		//        callable.Scope = Versions.versions;
		//        Expression e = callable.GetExpression().Optimize();
		//        return e.Optimize().Optimize();
		//    }
		//}

		//public class OpimtizedExpression : Test
		//{
		//    public override object GetResult(out int level)
		//    {
		//        level = 2;
		//        string path = Path.Combine(Interpreter.InstallationPath, @"basicTest.meta");
		//        Directory.SetCurrentDirectory(Path.GetDirectoryName(path));
		//        Map callable = Parser.Parse(path);
		//        callable.Scope = Gac.gac["library"];
		//        Gac.gac.Scope = new DirectoryMap(Path.GetDirectoryName(path));
		//        return callable.GetExpression().Optimize();
		//    }
		//}

		public class Subclass : SubclassTest
		{
			protected override string GetString(string whatever)
			{
				return "Test in child";
			}
		}
		public class SubclassTest
		{
			protected virtual string GetString(string whatever)
			{
				return "in base class";
			}
		}
		public class MemberTest
		{
			public string Overloaded(ArrayList list)
			{
				return "overloaded array list";
			}
			public string Overloaded(string test)
			{
				return "overloaded string";
			}
			public void TestVoid()
			{
			}
			public static void Compile(int i)
			{
				Console.WriteLine("hello");
			}
			public static string classField = "default";
			public string instanceField = "default";
			public static string OverloadedMethod(string argument)
			{
				return "string function, argument+" + argument;
			}
			public static string OverloadedMethod(int argument)
			{
				return "integer function, argument+" + argument;
			}
			public static string OverloadedMethod(MemberTest memberTest,int argument)
			{
				return "MemberTest function, argument+" + memberTest + argument;
			}
			public static string ClassProperty
			{
				get
				{
					return classField;
				}
				set
				{
					classField = value;
				}
			}
			public string InstanceProperty
			{
				get
				{
					return this.instanceField;
				}
				set
				{
					this.instanceField = value;
				}
			}
		}
	}
	public delegate object IntEvent(object intArg);
	public delegate object NormalEvent(object sender);

	public class TestClass
	{
		public class NestedClass
		{
			public static int field = 0;
		}
		public TestClass()
		{
		}
		public object CallInstanceEvent(object intArg)
		{
			return instanceEvent(intArg);
		}
		public static object CallStaticEvent(object sender)
		{
			return staticEvent(sender);
		}
		public event IntEvent instanceEvent;
		public static event NormalEvent staticEvent;
		protected string x = "unchangedX";
		protected string y = "unchangedY";
		protected string z = "unchangedZ";
		public static bool boolTest = false;

		public static object TestClass_staticEvent(object sender)
		{
			MethodBase[] m = typeof(TestClass).GetMethods();
			return null;
		}
		public delegate string TestDelegate(string x);
		public static Delegate del;
		public static void TakeDelegate(TestDelegate d)
		{
			del = d;
		}
		public static object GetResultFromDelegate()
		{
			return del.DynamicInvoke(new object[] { "argumentString" });
		}
		public double doubleValue = 0.0;
		public float floatValue = 0.0F;
		public decimal decimalValue = 0.0M;
	}
	public class PositionalNoConversion : TestClass
	{
		public PositionalNoConversion(string p1, string b, string p2)
		{
			this.x = p1;
			this.y = b;
			this.z = p2;
		}
		public string Concatenate(string p1, string b, string c)
		{
			return p1 + b + c + this.x + this.y + this.z;
		}
	}
	public class NamedNoConversion : TestClass
	{
		public NamedNoConversion(Map arg)
		{
			Map def = new DictionaryMap();
			def[1] = "null";
			def["y"] = "null";
			def["p2"] = "null";
			if (arg.ContainsKey(1))
			{
				def[1] = arg[1];
			}
			if (arg.ContainsKey("y"))
			{
				def["y"] = arg["y"];
			}
			if (arg.ContainsKey("p2"))
			{
				def["y2"] = arg["y2"];
			}
			this.x = def[1].GetString();
			this.y = def["y"].GetString();
			this.z = def["p2"].GetString();
		}
		public string Concatenate(Map arg)
		{
			Map def = new DictionaryMap();
			def[1] = "null";
			def["b"] = "null";
			def["c"] = "null";
			if (arg.ContainsKey(1))
			{
				def[1] = arg[1];
			}
			if (arg.ContainsKey("b"))
			{
				def["b"] = arg["b"];
			}
			if (arg.ContainsKey("c"))
			{
				def["c"] = arg["c"];
			}
			return def[1].GetString() + def["b"].GetString() + def["c"].GetString() + this.x + this.y + this.z;
		}
	}
	public class IndexerNoConversion : TestClass
	{
		public string this[string a]
		{
			get
			{
				return this.x + this.y + this.z + a;
			}
			set
			{
				this.x = a + value;
			}
		}
	}
}